farce 0 → 0.1.0

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 (420) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/CODE_OF_CONDUCT.md +26 -0
  4. data/CONTRIBUTING.md +71 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +1525 -0
  7. data/SECURITY.md +10 -0
  8. data/docs/benchmarks.md +185 -0
  9. data/docs/gems/dry-types.md +290 -0
  10. data/docs/gems/msgpack.md +70 -0
  11. data/docs/gems/ractor-shim.md +63 -0
  12. data/docs/modes.md +628 -0
  13. data/docs/scopes.md +649 -0
  14. data/docs/variants.md +346 -0
  15. data/ext/ext_helper.rb +20 -0
  16. data/ext/farce/README.md +21 -0
  17. data/ext/farce/atom.c +1023 -0
  18. data/ext/farce/bounded_map.c +1683 -0
  19. data/ext/farce/containers.h +77 -0
  20. data/ext/farce/counter.c +399 -0
  21. data/ext/farce/darwin.c +100 -0
  22. data/ext/farce/depend +12 -0
  23. data/ext/farce/dict.c +1523 -0
  24. data/ext/farce/dict.h +152 -0
  25. data/ext/farce/drivers.c +237 -0
  26. data/ext/farce/exchanger.c +299 -0
  27. data/ext/farce/extconf.rb +99 -0
  28. data/ext/farce/farce.c +359 -0
  29. data/ext/farce/flag.c +288 -0
  30. data/ext/farce/io.c +338 -0
  31. data/ext/farce/lock.c +510 -0
  32. data/ext/farce/map.c +2240 -0
  33. data/ext/farce/priority_queue.c +2056 -0
  34. data/ext/farce/queue.c +1059 -0
  35. data/ext/farce/reactor.c +820 -0
  36. data/ext/farce/reactor.h +103 -0
  37. data/ext/farce/shareable.h +31 -0
  38. data/ext/farce/signal.c +350 -0
  39. data/ext/farce/transaction.c +354 -0
  40. data/ext/farce/transaction.h +40 -0
  41. data/ext/farce/tree_map.c +1953 -0
  42. data/ext/farce/trie.c +2020 -0
  43. data/ext/farce/unshareable.c +155 -0
  44. data/ext/farce/unshared_io_pool.h +234 -0
  45. data/ext/farce/unshared_signal.c +263 -0
  46. data/ext/farce/unshared_wait.h +193 -0
  47. data/ext/farce/unsupported.c +6 -0
  48. data/ext/farce/vector.c +1195 -0
  49. data/ext/farce/weak_map.c +1714 -0
  50. data/ext/java/org/farce/BoundedMap.java +394 -0
  51. data/ext/java/org/farce/FiberScheduler.java +141 -0
  52. data/ext/java/org/farce/PriorityKey.java +45 -0
  53. data/ext/java/org/farce/PriorityQueue.java +373 -0
  54. data/ext/java/org/farce/QueueSignal.java +28 -0
  55. data/ext/rebind/README.md +14 -0
  56. data/ext/rebind/extconf.rb +10 -0
  57. data/ext/rebind/rebind.c +186 -0
  58. data/lib/farce/_yard/internal.rb +13 -0
  59. data/lib/farce/_yard/macros.rb +61 -0
  60. data/lib/farce/_yard/ractor.rb +46 -0
  61. data/lib/farce/abstract/atom.rb +186 -0
  62. data/lib/farce/abstract/bounded_map.rb +232 -0
  63. data/lib/farce/abstract/collection.rb +151 -0
  64. data/lib/farce/abstract/concurrent_map.rb +381 -0
  65. data/lib/farce/abstract/counter.rb +193 -0
  66. data/lib/farce/abstract/duplicable_map.rb +229 -0
  67. data/lib/farce/abstract/exchanger.rb +26 -0
  68. data/lib/farce/abstract/flag.rb +71 -0
  69. data/lib/farce/abstract/lazy.rb +115 -0
  70. data/lib/farce/abstract/lease.rb +104 -0
  71. data/lib/farce/abstract/lease_map.rb +261 -0
  72. data/lib/farce/abstract/lease_pool.rb +91 -0
  73. data/lib/farce/abstract/lfu_map.rb +20 -0
  74. data/lib/farce/abstract/lru_map.rb +25 -0
  75. data/lib/farce/abstract/map.rb +345 -0
  76. data/lib/farce/abstract/molecule.rb +245 -0
  77. data/lib/farce/abstract/port.rb +74 -0
  78. data/lib/farce/abstract/priority_queue.rb +117 -0
  79. data/lib/farce/abstract/queue.rb +269 -0
  80. data/lib/farce/abstract/scheduler.rb +111 -0
  81. data/lib/farce/abstract/set.rb +910 -0
  82. data/lib/farce/abstract/sorted_set.rb +172 -0
  83. data/lib/farce/abstract/timer_queue.rb +136 -0
  84. data/lib/farce/abstract/tree_map.rb +269 -0
  85. data/lib/farce/abstract/value.rb +68 -0
  86. data/lib/farce/abstract/vector.rb +1126 -0
  87. data/lib/farce/abstract/weak_atom.rb +32 -0
  88. data/lib/farce/abstract/weak_key_map.rb +12 -0
  89. data/lib/farce/abstract/weak_map.rb +13 -0
  90. data/lib/farce/abstract/weak_set.rb +12 -0
  91. data/lib/farce/abstract/weak_value_map.rb +12 -0
  92. data/lib/farce/abstract.rb +17 -0
  93. data/lib/farce/atom.rb +293 -0
  94. data/lib/farce/class_mirror.rb +87 -0
  95. data/lib/farce/clock.rb +121 -0
  96. data/lib/farce/config.rb +229 -0
  97. data/lib/farce/counter.rb +71 -0
  98. data/lib/farce/deduper.rb +122 -0
  99. data/lib/farce/engine/jruby/bounded_map.rb +314 -0
  100. data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
  101. data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
  102. data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
  103. data/lib/farce/engine/jruby/map.rb +505 -0
  104. data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
  105. data/lib/farce/engine/jruby/signal.rb +147 -0
  106. data/lib/farce/engine/jruby.rb +63 -0
  107. data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
  108. data/lib/farce/engine/jvm/counter.rb +102 -0
  109. data/lib/farce/engine/jvm/extension.rb +32 -0
  110. data/lib/farce/engine/jvm/farce.jar +0 -0
  111. data/lib/farce/engine/jvm/flag.rb +79 -0
  112. data/lib/farce/engine/jvm/priority_queue.rb +217 -0
  113. data/lib/farce/engine/jvm/tree_map.rb +350 -0
  114. data/lib/farce/engine/jvm/types.rb +180 -0
  115. data/lib/farce/engine/jvm.rb +19 -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/vault.rb +56 -0
  121. data/lib/farce/engine/ruby/4.0/port.rb +19 -0
  122. data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
  123. data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
  124. data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
  125. data/lib/farce/engine/ruby/4.1/port.rb +21 -0
  126. data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
  127. data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
  128. data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
  129. data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
  130. data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
  131. data/lib/farce/engine/ruby/shared/lease.rb +26 -0
  132. data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
  133. data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
  134. data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
  135. data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
  136. data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
  137. data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
  138. data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
  139. data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
  140. data/lib/farce/engine/ruby/shared/vault.rb +144 -0
  141. data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
  142. data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
  143. data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
  144. data/lib/farce/engine/ruby.rb +130 -0
  145. data/lib/farce/engine/shared/atom.rb +10 -0
  146. data/lib/farce/engine/shared/exchanger.rb +130 -0
  147. data/lib/farce/engine/shared/identity_key.rb +22 -0
  148. data/lib/farce/engine/shared/lease.rb +10 -0
  149. data/lib/farce/engine/shared/lease_pool.rb +10 -0
  150. data/lib/farce/engine/shared/main_scheduler.rb +20 -0
  151. data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
  152. data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
  153. data/lib/farce/engine/shared/port.rb +44 -0
  154. data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
  155. data/lib/farce/engine/shared/proxy_owner.rb +43 -0
  156. data/lib/farce/engine/shared/queue.rb +233 -0
  157. data/lib/farce/engine/shared/ractor_methods.rb +73 -0
  158. data/lib/farce/engine/shared/rebindable.rb +15 -0
  159. data/lib/farce/engine/shared/strict_atom.rb +73 -0
  160. data/lib/farce/engine/shared/strict_map.rb +117 -0
  161. data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
  162. data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
  163. data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
  164. data/lib/farce/engine/shared/trie.rb +317 -0
  165. data/lib/farce/engine/shared/trie_builder.rb +199 -0
  166. data/lib/farce/engine/shared/unshareable.rb +14 -0
  167. data/lib/farce/engine/shared/unshared_atom.rb +256 -0
  168. data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
  169. data/lib/farce/engine/shared/unshared_queue.rb +18 -0
  170. data/lib/farce/engine/shared/unshared_signal.rb +21 -0
  171. data/lib/farce/engine/shared/unshared_vector.rb +377 -0
  172. data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
  173. data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
  174. data/lib/farce/engine/shared/vault.rb +31 -0
  175. data/lib/farce/engine/shared/vector.rb +83 -0
  176. data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
  177. data/lib/farce/engine/shared/weak_atom.rb +20 -0
  178. data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
  179. data/lib/farce/engine/shared/weak_map/index.rb +249 -0
  180. data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
  181. data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
  182. data/lib/farce/engine/shared.rb +63 -0
  183. data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
  184. data/lib/farce/engine/truffleruby/lock.rb +121 -0
  185. data/lib/farce/engine/truffleruby/map.rb +656 -0
  186. data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
  187. data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
  188. data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
  189. data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
  190. data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
  191. data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
  192. data/lib/farce/engine/truffleruby/signal.rb +77 -0
  193. data/lib/farce/engine/truffleruby.rb +148 -0
  194. data/lib/farce/envelope.rb +335 -0
  195. data/lib/farce/error.rb +35 -0
  196. data/lib/farce/exchanger.rb +41 -0
  197. data/lib/farce/flag.rb +27 -0
  198. data/lib/farce/integrations/active_support/blank.rb +68 -0
  199. data/lib/farce/integrations/active_support/clock.rb +17 -0
  200. data/lib/farce/integrations/active_support/duplicable.rb +78 -0
  201. data/lib/farce/integrations/active_support/map.rb +175 -0
  202. data/lib/farce/integrations/active_support/set.rb +60 -0
  203. data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
  204. data/lib/farce/integrations/active_support/vector.rb +231 -0
  205. data/lib/farce/integrations/active_support.rb +9 -0
  206. data/lib/farce/integrations/activesupport.rb +5 -0
  207. data/lib/farce/integrations/bson.rb +108 -0
  208. data/lib/farce/integrations/cbor.rb +51 -0
  209. data/lib/farce/integrations/concurrent.rb +112 -0
  210. data/lib/farce/integrations/dry-types.rb +5 -0
  211. data/lib/farce/integrations/dry_types.rb +694 -0
  212. data/lib/farce/integrations/json.rb +7 -0
  213. data/lib/farce/integrations/msgpack.rb +112 -0
  214. data/lib/farce/integrations/oj.rb +69 -0
  215. data/lib/farce/integrations/psych.rb +191 -0
  216. data/lib/farce/integrations/ractor-sharing.rb +5 -0
  217. data/lib/farce/integrations/ractor-tmvar.rb +5 -0
  218. data/lib/farce/integrations/ractor_sharing.rb +172 -0
  219. data/lib/farce/integrations/ractor_tmvar.rb +64 -0
  220. data/lib/farce/integrations/shared/to_json.rb +42 -0
  221. data/lib/farce/integrations/sorted_set.rb +11 -0
  222. data/lib/farce/integrations/weakref.rb +38 -0
  223. data/lib/farce/integrations/yajl.rb +10 -0
  224. data/lib/farce/integrations.rb +156 -0
  225. data/lib/farce/internal/_frozen_config.rb +11 -0
  226. data/lib/farce/internal/autoloads.rb +47 -0
  227. data/lib/farce/internal/blocking_priority_queue.rb +122 -0
  228. data/lib/farce/internal/converter.rb +106 -0
  229. data/lib/farce/internal/copyable.rb +31 -0
  230. data/lib/farce/internal/delegation.rb +20 -0
  231. data/lib/farce/internal/external_transaction.rb +59 -0
  232. data/lib/farce/internal/fake_ractor.rb +179 -0
  233. data/lib/farce/internal/freeze.rb +118 -0
  234. data/lib/farce/internal/inspect.rb +157 -0
  235. data/lib/farce/internal/key_lock_map.rb +29 -0
  236. data/lib/farce/internal/key_normalizer.rb +289 -0
  237. data/lib/farce/internal/lease_initialization.rb +115 -0
  238. data/lib/farce/internal/lease_map.rb +441 -0
  239. data/lib/farce/internal/lease_pool_state.rb +228 -0
  240. data/lib/farce/internal/lease_state.rb +342 -0
  241. data/lib/farce/internal/lease_waiting.rb +13 -0
  242. data/lib/farce/internal/managed_queue.rb +26 -0
  243. data/lib/farce/internal/map_value_modes.rb +227 -0
  244. data/lib/farce/internal/marshal_support.rb +227 -0
  245. data/lib/farce/internal/mixin.rb +20 -0
  246. data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
  247. data/lib/farce/internal/noncopyable.rb +17 -0
  248. data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
  249. data/lib/farce/internal/pool_supervisor.rb +41 -0
  250. data/lib/farce/internal/pool_worker.rb +61 -0
  251. data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
  252. data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
  253. data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
  254. data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
  255. data/lib/farce/internal/portable_transaction.rb +164 -0
  256. data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
  257. data/lib/farce/internal/reservation_waiting.rb +24 -0
  258. data/lib/farce/internal/scheduled_task.rb +48 -0
  259. data/lib/farce/internal/scheduler_io.rb +171 -0
  260. data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
  261. data/lib/farce/internal/select_scheduler.rb +235 -0
  262. data/lib/farce/internal/storage.rb +162 -0
  263. data/lib/farce/internal/strict_lease.rb +30 -0
  264. data/lib/farce/internal/strict_lease_map.rb +20 -0
  265. data/lib/farce/internal/strict_lease_pool.rb +29 -0
  266. data/lib/farce/internal/thread_pool.rb +166 -0
  267. data/lib/farce/internal/transaction_conflict.rb +9 -0
  268. data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
  269. data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
  270. data/lib/farce/internal/undefined.rb +22 -0
  271. data/lib/farce/internal/unshared_lease.rb +29 -0
  272. data/lib/farce/internal/unshared_lease_pool.rb +34 -0
  273. data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
  274. data/lib/farce/internal/value_serialization.rb +13 -0
  275. data/lib/farce/internal/weak_map_value_modes.rb +58 -0
  276. data/lib/farce/internal/weak_mode_manager.rb +26 -0
  277. data/lib/farce/internal.rb +129 -0
  278. data/lib/farce/lazy.rb +100 -0
  279. data/lib/farce/lazy_ref.rb +40 -0
  280. data/lib/farce/lease.rb +28 -0
  281. data/lib/farce/lease_map.rb +34 -0
  282. data/lib/farce/lease_pool.rb +29 -0
  283. data/lib/farce/lfu_map.rb +53 -0
  284. data/lib/farce/local/atom.rb +23 -0
  285. data/lib/farce/local/counter.rb +88 -0
  286. data/lib/farce/local/flag.rb +65 -0
  287. data/lib/farce/local/lazy.rb +38 -0
  288. data/lib/farce/local/lazy_ref.rb +36 -0
  289. data/lib/farce/local/lease.rb +77 -0
  290. data/lib/farce/local/lease_map.rb +80 -0
  291. data/lib/farce/local/lease_pool.rb +38 -0
  292. data/lib/farce/local/lfu_map.rb +55 -0
  293. data/lib/farce/local/lru_map.rb +62 -0
  294. data/lib/farce/local/map.rb +47 -0
  295. data/lib/farce/local/molecule.rb +45 -0
  296. data/lib/farce/local/priority_queue.rb +53 -0
  297. data/lib/farce/local/queue.rb +32 -0
  298. data/lib/farce/local/scoped.rb +166 -0
  299. data/lib/farce/local/set.rb +18 -0
  300. data/lib/farce/local/sorted_set.rb +50 -0
  301. data/lib/farce/local/timer_queue.rb +41 -0
  302. data/lib/farce/local/tree_map.rb +47 -0
  303. data/lib/farce/local/vector.rb +30 -0
  304. data/lib/farce/local/weak_atom.rb +23 -0
  305. data/lib/farce/local/weak_key_map.rb +39 -0
  306. data/lib/farce/local/weak_map.rb +39 -0
  307. data/lib/farce/local/weak_set.rb +18 -0
  308. data/lib/farce/local/weak_value_map.rb +39 -0
  309. data/lib/farce/local.rb +35 -0
  310. data/lib/farce/lock.rb +54 -0
  311. data/lib/farce/lru_map.rb +63 -0
  312. data/lib/farce/map.rb +58 -0
  313. data/lib/farce/mode_manager.rb +142 -0
  314. data/lib/farce/molecule.rb +60 -0
  315. data/lib/farce/mutable.rb +171 -0
  316. data/lib/farce/pool.rb +332 -0
  317. data/lib/farce/port.rb +134 -0
  318. data/lib/farce/priority_queue.rb +70 -0
  319. data/lib/farce/proxy/register.rb +101 -0
  320. data/lib/farce/proxy/supervisor.rb +137 -0
  321. data/lib/farce/proxy/wrapper.rb +49 -0
  322. data/lib/farce/proxy.rb +291 -0
  323. data/lib/farce/queue.rb +60 -0
  324. data/lib/farce/ractor.rb +269 -0
  325. data/lib/farce/read_write_lock.rb +256 -0
  326. data/lib/farce/reference.rb +158 -0
  327. data/lib/farce/resolv/dns.rb +42 -0
  328. data/lib/farce/resolv.rb +85 -0
  329. data/lib/farce/scheduler.rb +536 -0
  330. data/lib/farce/set.rb +39 -0
  331. data/lib/farce/shareable.rb +150 -0
  332. data/lib/farce/signal.rb +97 -0
  333. data/lib/farce/sorted_set.rb +36 -0
  334. data/lib/farce/strict/atom.rb +34 -0
  335. data/lib/farce/strict/counter.rb +10 -0
  336. data/lib/farce/strict/exchanger.rb +25 -0
  337. data/lib/farce/strict/flag.rb +10 -0
  338. data/lib/farce/strict/lazy.rb +26 -0
  339. data/lib/farce/strict/lazy_ref.rb +26 -0
  340. data/lib/farce/strict/lease.rb +27 -0
  341. data/lib/farce/strict/lease_map.rb +33 -0
  342. data/lib/farce/strict/lease_pool.rb +28 -0
  343. data/lib/farce/strict/lfu_map.rb +27 -0
  344. data/lib/farce/strict/lru_map.rb +28 -0
  345. data/lib/farce/strict/map.rb +54 -0
  346. data/lib/farce/strict/molecule.rb +16 -0
  347. data/lib/farce/strict/port.rb +40 -0
  348. data/lib/farce/strict/priority_queue.rb +20 -0
  349. data/lib/farce/strict/queue.rb +17 -0
  350. data/lib/farce/strict/set.rb +14 -0
  351. data/lib/farce/strict/sorted_set.rb +19 -0
  352. data/lib/farce/strict/timer_queue.rb +13 -0
  353. data/lib/farce/strict/tree_map.rb +27 -0
  354. data/lib/farce/strict/vector.rb +24 -0
  355. data/lib/farce/strict/weak_atom.rb +31 -0
  356. data/lib/farce/strict/weak_key_map.rb +49 -0
  357. data/lib/farce/strict/weak_map.rb +49 -0
  358. data/lib/farce/strict/weak_set.rb +14 -0
  359. data/lib/farce/strict/weak_value_map.rb +48 -0
  360. data/lib/farce/strict.rb +28 -0
  361. data/lib/farce/system.rb +40 -0
  362. data/lib/farce/thread_scheduler.rb +70 -0
  363. data/lib/farce/timer_queue.rb +66 -0
  364. data/lib/farce/transaction/atom.rb +73 -0
  365. data/lib/farce/transaction/map.rb +25 -0
  366. data/lib/farce/transaction/map_operations.rb +143 -0
  367. data/lib/farce/transaction/molecule.rb +90 -0
  368. data/lib/farce/transaction/mutable.rb +61 -0
  369. data/lib/farce/transaction/set.rb +17 -0
  370. data/lib/farce/transaction/set_operations.rb +48 -0
  371. data/lib/farce/transaction/sorted_set.rb +18 -0
  372. data/lib/farce/transaction/tree_map.rb +78 -0
  373. data/lib/farce/transaction/vector.rb +139 -0
  374. data/lib/farce/transaction/wrapper.rb +202 -0
  375. data/lib/farce/transaction.rb +343 -0
  376. data/lib/farce/tree_map.rb +56 -0
  377. data/lib/farce/unsafe/lfu_map.rb +36 -0
  378. data/lib/farce/unsafe/lru_map.rb +36 -0
  379. data/lib/farce/unsafe/tree_map.rb +21 -0
  380. data/lib/farce/unsafe.rb +29 -0
  381. data/lib/farce/unshareable.rb +67 -0
  382. data/lib/farce/unshared/atom.rb +24 -0
  383. data/lib/farce/unshared/counter.rb +10 -0
  384. data/lib/farce/unshared/flag.rb +10 -0
  385. data/lib/farce/unshared/lazy.rb +38 -0
  386. data/lib/farce/unshared/lazy_ref.rb +26 -0
  387. data/lib/farce/unshared/lease.rb +27 -0
  388. data/lib/farce/unshared/lease_map.rb +26 -0
  389. data/lib/farce/unshared/lease_pool.rb +25 -0
  390. data/lib/farce/unshared/lfu_map.rb +20 -0
  391. data/lib/farce/unshared/lru_map.rb +20 -0
  392. data/lib/farce/unshared/map.rb +49 -0
  393. data/lib/farce/unshared/molecule.rb +16 -0
  394. data/lib/farce/unshared/priority_queue.rb +16 -0
  395. data/lib/farce/unshared/queue.rb +27 -0
  396. data/lib/farce/unshared/set.rb +14 -0
  397. data/lib/farce/unshared/sorted_set.rb +28 -0
  398. data/lib/farce/unshared/timer_queue.rb +16 -0
  399. data/lib/farce/unshared/tree_map.rb +21 -0
  400. data/lib/farce/unshared/vector.rb +19 -0
  401. data/lib/farce/unshared/weak_atom.rb +31 -0
  402. data/lib/farce/unshared/weak_key_map.rb +44 -0
  403. data/lib/farce/unshared/weak_map.rb +44 -0
  404. data/lib/farce/unshared/weak_set.rb +14 -0
  405. data/lib/farce/unshared/weak_value_map.rb +43 -0
  406. data/lib/farce/unshared.rb +28 -0
  407. data/lib/farce/vector.rb +228 -0
  408. data/lib/farce/version.rb +8 -0
  409. data/lib/farce/walker/definitions.rb +186 -0
  410. data/lib/farce/walker/modification.rb +355 -0
  411. data/lib/farce/walker.rb +319 -0
  412. data/lib/farce/weak_atom.rb +121 -0
  413. data/lib/farce/weak_key_map.rb +31 -0
  414. data/lib/farce/weak_map.rb +33 -0
  415. data/lib/farce/weak_ref.rb +67 -0
  416. data/lib/farce/weak_set.rb +82 -0
  417. data/lib/farce/weak_value.rb +195 -0
  418. data/lib/farce/weak_value_map.rb +32 -0
  419. data/lib/farce.rb +519 -0
  420. metadata +435 -8
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # @!visibility private
7
+ module Internal # :nodoc: all
8
+ class Counter < Numeric
9
+ attr_reader :initial
10
+
11
+ def initialize(value = 0)
12
+ raise "Counter is already initialized" if defined?(@reference)
13
+ check_frozen!
14
+ raise TypeError, "initial value must be an Integer" unless value.is_a?(Integer)
15
+ @signal = Signal.new
16
+ @initial = value
17
+ @reference = TruffleRuby::AtomicReference.new(value)
18
+ super()
19
+ end
20
+
21
+ def get = @reference.get
22
+
23
+ def store(value)
24
+ check_frozen!
25
+ raise TypeError, "value must be an Integer" unless value.is_a?(Integer)
26
+ @reference.set(value)
27
+ @signal.broadcast
28
+ value
29
+ end
30
+
31
+ def swap(value)
32
+ check_frozen!
33
+ raise TypeError, "value must be an Integer" unless value.is_a?(Integer)
34
+ @reference.get_and_set(value).tap { @signal.broadcast }
35
+ end
36
+
37
+ def compare_and_set(expected_value, new_value)
38
+ check_frozen!
39
+ raise TypeError, "expected value must be an Integer" unless expected_value.is_a?(Integer)
40
+ raise TypeError, "replacement value must be an Integer" unless new_value.is_a?(Integer)
41
+ @reference.compare_and_set(expected_value, new_value).tap { @signal.broadcast }
42
+ end
43
+
44
+ def add(delta = 1)
45
+ check_frozen!
46
+ raise TypeError, "delta must be an Integer" unless delta.is_a?(Integer)
47
+ change(delta)
48
+ end
49
+
50
+ def subtract(delta = 1)
51
+ check_frozen!
52
+ raise TypeError, "delta must be an Integer" unless delta.is_a?(Integer)
53
+ change(-delta)
54
+ end
55
+
56
+ def increment(delta = 1)
57
+ check_frozen!
58
+ unless delta.is_a?(Integer)
59
+ delta = Integer(delta)
60
+ check_frozen!
61
+ end
62
+ change(delta)
63
+ self
64
+ end
65
+
66
+ def decrement(delta = 1)
67
+ check_frozen!
68
+ unless delta.is_a?(Integer)
69
+ delta = Integer(delta)
70
+ check_frozen!
71
+ end
72
+ change(-delta)
73
+ self
74
+ end
75
+
76
+ alias value get
77
+ alias value= store
78
+
79
+ def change_signal = @signal
80
+
81
+ private
82
+
83
+ def check_frozen!
84
+ raise FrozenError.new("can't modify frozen #{self.class}", receiver: self) if frozen?
85
+ end
86
+
87
+ def change(delta)
88
+ loop do
89
+ old_value = @reference.get
90
+ new_value = old_value + delta
91
+ if @reference.compare_and_set(old_value, new_value)
92
+ @signal.broadcast
93
+ return new_value
94
+ end
95
+ end
96
+ end
97
+
98
+ def initialize_copy(other)
99
+ @signal = Signal.new
100
+ @initial = other.initial
101
+ @reference = TruffleRuby::AtomicReference.new(other.value)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # @!visibility private
7
+ module Internal # :nodoc: all
8
+ class Flag
9
+ def initialize(value = false) # rubocop:disable Style/OptionalBooleanParameter
10
+ raise "Flag is already initialized" if defined?(@reference)
11
+ check_frozen!
12
+ @reference = TruffleRuby::AtomicReference.new(validate_boolean(value, "initial value"))
13
+ end
14
+
15
+ def value = @reference.get
16
+
17
+ def set # rubocop:disable Naming/PredicateMethod
18
+ check_frozen!
19
+ @reference.set(true)
20
+ true
21
+ end
22
+
23
+ def unset # rubocop:disable Naming/PredicateMethod
24
+ check_frozen!
25
+ @reference.set(false)
26
+ false
27
+ end
28
+
29
+ def store(value)
30
+ check_frozen!
31
+ value = validate_boolean(value, "value")
32
+ @reference.set(value)
33
+ value
34
+ end
35
+
36
+ def swap(value)
37
+ check_frozen!
38
+ value = validate_boolean(value, "value")
39
+ @reference.get_and_set(value)
40
+ end
41
+
42
+ def compare_and_set(expected_value, replacement_value)
43
+ check_frozen!
44
+ expected_value = validate_boolean(expected_value, "expected value")
45
+ replacement_value = validate_boolean(replacement_value, "replacement value")
46
+ @reference.compare_and_set(expected_value, replacement_value)
47
+ end
48
+
49
+ def toggle
50
+ check_frozen!
51
+ loop do
52
+ current = @reference.get
53
+ replacement = !current
54
+ return replacement if @reference.compare_and_set(current, replacement)
55
+ end
56
+ end
57
+
58
+ alias get value
59
+ alias value= store
60
+
61
+ private
62
+
63
+ def check_frozen!
64
+ raise FrozenError.new("can't modify frozen #{self.class}", receiver: self) if frozen?
65
+ end
66
+
67
+ def validate_boolean(value, name)
68
+ return value if value.equal?(true) || value.equal?(false)
69
+ raise ArgumentError, "#{name} must be true or false"
70
+ end
71
+
72
+ def initialize_copy(other)
73
+ @reference = TruffleRuby::AtomicReference.new(other.value)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # @!visibility private
7
+ module Internal # :nodoc: all
8
+ # Low-level operations shared by native TruffleRuby's ordered arrays.
9
+ # Bound primitive methods protect stored String snapshots and identity
10
+ # checks from user overrides.
11
+ module TruffleOrderedArraySupport
12
+ INTERRUPT_IMMEDIATE = { Exception => :immediate }.freeze
13
+ BASIC_OBJECT_EQUAL = BasicObject.instance_method(:equal?)
14
+ CLASS_ALLOCATE = Class.instance_method(:allocate)
15
+ OBJECT_CLASS = Object.instance_method(:class)
16
+ OBJECT_FREEZE = Object.instance_method(:freeze)
17
+ OBJECT_FROZEN = Object.instance_method(:frozen?)
18
+ OBJECT_INSTANCE_VARIABLES = Object.instance_method(:instance_variables)
19
+ OBJECT_INSTANCE_VARIABLE_GET = Object.instance_method(:instance_variable_get)
20
+ OBJECT_INSTANCE_VARIABLE_SET = Object.instance_method(:instance_variable_set)
21
+ OBJECT_IS_A = Object.instance_method(:is_a?)
22
+ STRING_INITIALIZE_COPY = String.instance_method(:initialize_copy)
23
+ STRING_UMINUS = String.instance_method(:-@)
24
+
25
+ private_constant :BASIC_OBJECT_EQUAL, :CLASS_ALLOCATE, :OBJECT_CLASS, :OBJECT_FREEZE,
26
+ :OBJECT_FROZEN, :OBJECT_INSTANCE_VARIABLES,
27
+ :OBJECT_INSTANCE_VARIABLE_GET, :OBJECT_INSTANCE_VARIABLE_SET,
28
+ :OBJECT_IS_A, :STRING_INITIALIZE_COPY, :STRING_UMINUS
29
+
30
+ private
31
+
32
+ def primitive_freeze(object) = OBJECT_FREEZE.bind_call(object)
33
+ def primitive_frozen?(object) = OBJECT_FROZEN.bind_call(object)
34
+ def primitive_is_a?(object, klass) = OBJECT_IS_A.bind_call(object, klass)
35
+ def primitive_identical?(left, right) = BASIC_OBJECT_EQUAL.bind_call(left, right)
36
+
37
+ def canonical_ordered_key(key)
38
+ return key unless primitive_is_a?(key, String)
39
+ return STRING_UMINUS.bind_call(key) if
40
+ primitive_identical?(OBJECT_CLASS.bind_call(key), String)
41
+
42
+ snapshot_ordered_key(key)
43
+ end
44
+
45
+ def snapshot_ordered_key(key)
46
+ return key unless primitive_is_a?(key, String)
47
+
48
+ copy = CLASS_ALLOCATE.bind_call(OBJECT_CLASS.bind_call(key))
49
+ STRING_INITIALIZE_COPY.bind_call(copy, key)
50
+ OBJECT_INSTANCE_VARIABLES.bind_call(key).each do |name|
51
+ value = OBJECT_INSTANCE_VARIABLE_GET.bind_call(key, name)
52
+ OBJECT_INSTANCE_VARIABLE_SET.bind_call(copy, name, value)
53
+ end
54
+ primitive_freeze(copy)
55
+ end
56
+
57
+ def without_async_interrupts(&)
58
+ Thread.handle_interrupt(INTERRUPT_MASK, &)
59
+ end
60
+
61
+ def with_interruptible_callbacks(&)
62
+ Thread.handle_interrupt(INTERRUPT_IMMEDIATE, &)
63
+ end
64
+ end
65
+ private_constant :TruffleOrderedArraySupport
66
+ end
67
+ end
@@ -0,0 +1,388 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/truffleruby/native/ordered_array_support"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ # Synchronized minimum-priority queue for native TruffleRuby. Binary
11
+ # search locates a priority bucket, whose small Array preserves FIFO order.
12
+ class PriorityQueue
13
+ include TruffleOrderedArraySupport
14
+ include Freeze::Unfreezable
15
+
16
+ DEFAULT_CAPACITY = nil
17
+ EMPTY = Object.new.freeze
18
+ INITIALIZATION_LOCK = Mutex.new
19
+ private_constant :DEFAULT_CAPACITY, :EMPTY, :INITIALIZATION_LOCK
20
+
21
+ Bucket = Struct.new(:priority, :items)
22
+ TrackedItem = Struct.new(:value, :enqueued_at)
23
+ private_constant :Bucket, :TrackedItem
24
+
25
+ class State
26
+ attr_accessor :size, :sealed, :closed, :generation, :operation_owner
27
+ attr_reader :buckets, :capacity, :signal, :lock, :tracked_items, :track_age
28
+
29
+ def initialize(capacity:, signal:, lock:, track_age:)
30
+ @buckets = []
31
+ @capacity = capacity
32
+ @signal = signal
33
+ @lock = lock
34
+ @size = 0
35
+ @sealed = false
36
+ @closed = false
37
+ @track_age = track_age
38
+ @tracked_items = [] if track_age
39
+ @generation = 0
40
+ @operation_owner = nil
41
+ end
42
+ end
43
+ private_constant :State
44
+
45
+ def initialize(capacity: DEFAULT_CAPACITY, signal: nil, track_age: false)
46
+ ensure_initializable!
47
+ capacity = normalize_capacity(capacity)
48
+ signal = normalize_signal(signal)
49
+ prepared = State.new(capacity:, signal:, lock: Lock.new, track_age: track_age ? true : false)
50
+ commit_initialization(prepared)
51
+ end
52
+ private :initialize
53
+
54
+ def initialize_copy(_other)
55
+ raise TypeError, "priority queues cannot be copied"
56
+ end
57
+
58
+ def push(priority, value)
59
+ state = initialized_state
60
+ with_queue_operation(state) do
61
+ raise_closed if state.closed
62
+ raise_sealed if state.sealed
63
+ next false if state.capacity && state.size >= state.capacity
64
+
65
+ stored = state.track_age ? TrackedItem.new(value, Clock.now) : value
66
+
67
+ index, found = locate_priority(state.buckets, priority)
68
+ if found
69
+ bucket = state.buckets[index]
70
+ prepared_items = bucket.items.dup << stored
71
+ notify_and_commit(state) do
72
+ bucket.items = prepared_items
73
+ state.size += 1
74
+ track_push(state, stored)
75
+ end
76
+ else
77
+ pending = Bucket.new(snapshot_ordered_key(priority), [stored])
78
+ notify_and_commit(state) do
79
+ index, duplicate = with_interruptible_callbacks do
80
+ locate_priority(state.buckets, priority)
81
+ end
82
+ raise "priority comparator changed during insertion" if duplicate
83
+ state.buckets.insert(index, pending)
84
+ state.size += 1
85
+ track_push(state, stored)
86
+ end
87
+ end
88
+ true
89
+ end
90
+ end
91
+
92
+ def pop(&fallback)
93
+ pop_endpoint(last: false, fallback:)
94
+ end
95
+
96
+ def pop_last(&fallback)
97
+ pop_endpoint(last: true, fallback:)
98
+ end
99
+
100
+ def pop_before(latest_priority, &fallback)
101
+ pop_endpoint(last: false, fallback:, latest_priority:)
102
+ end
103
+
104
+ def peek(&fallback)
105
+ read_endpoint(:value, last: false, fallback:)
106
+ end
107
+
108
+ def peek_last(&fallback)
109
+ read_endpoint(:value, last: true, fallback:)
110
+ end
111
+
112
+ def peek_priority(&fallback)
113
+ read_endpoint(:priority, last: false, fallback:)
114
+ end
115
+
116
+ def peek_last_priority(&fallback)
117
+ read_endpoint(:priority, last: true, fallback:)
118
+ end
119
+
120
+ def delete(priority, value)
121
+ delete_value(priority, value, identity: false)
122
+ end
123
+
124
+ def delete_identity(priority, value)
125
+ delete_value(priority, value, identity: true)
126
+ end
127
+
128
+ def delete_match(priority, pattern)
129
+ delete_value(priority, pattern, identity: false, match: true)
130
+ end
131
+
132
+ def size
133
+ state = initialized_state
134
+ with_queue_operation(state) { state.size }
135
+ end
136
+
137
+ def empty?
138
+ state = initialized_state
139
+ with_queue_operation(state) { state.size.zero? } # rubocop:disable Style/ZeroLengthPredicate
140
+ end
141
+
142
+ def capacity = initialized_state.capacity
143
+
144
+ def clear
145
+ state = initialized_state
146
+ with_queue_operation(state) do
147
+ notify_and_commit(state) do
148
+ state.buckets.clear
149
+ state.generation += 1 if state.track_age && state.size.positive?
150
+ state.size = 0
151
+ state.tracked_items&.clear
152
+ state.closed = true if state.sealed
153
+ end
154
+ self
155
+ end
156
+ end
157
+
158
+ def close
159
+ state = initialized_state
160
+ with_queue_operation(state) do
161
+ notify_and_commit(state) do
162
+ state.generation += 1 if state.track_age && !state.closed
163
+ state.sealed = true
164
+ state.closed = true
165
+ end
166
+ self
167
+ end
168
+ end
169
+
170
+ def closed?
171
+ state = initialized_state
172
+ with_queue_operation(state) { state.closed }
173
+ end
174
+
175
+ def sealed?
176
+ state = initialized_state
177
+ with_queue_operation(state) { state.sealed }
178
+ end
179
+
180
+ def age_tracking? = initialized_state.track_age
181
+
182
+ def generation
183
+ state = initialized_state
184
+ with_queue_operation(state) { state.track_age ? state.generation : nil }
185
+ end
186
+
187
+ def oldest_enqueued_at
188
+ state = initialized_state
189
+ with_queue_operation(state) { state.tracked_items&.first&.enqueued_at }
190
+ end
191
+
192
+ def oldest_age
193
+ timestamp = oldest_enqueued_at
194
+ Clock.now - timestamp if timestamp
195
+ end
196
+
197
+ def seal
198
+ state = initialized_state
199
+ with_queue_operation(state) do
200
+ notify_and_commit(state) do
201
+ unless state.sealed
202
+ state.sealed = true
203
+ state.generation += 1 if state.track_age
204
+ end
205
+ state.closed = true if state.size.zero? # rubocop:disable Style/ZeroLengthPredicate
206
+ end
207
+ self
208
+ end
209
+ end
210
+
211
+ private
212
+
213
+ def pop_endpoint(last:, fallback:, latest_priority: UNDEFINED)
214
+ state = initialized_state
215
+ result = with_queue_operation(state) do
216
+ raise_closed if state.closed
217
+ bucket = last ? state.buckets.last : state.buckets.first
218
+ next EMPTY unless bucket
219
+ if !UNDEFINED.equal?(latest_priority) && compare_priorities(bucket.priority, latest_priority).positive?
220
+ next EMPTY
221
+ end
222
+
223
+ stored = bucket.items.first
224
+ prepared_items = bucket.items.drop(1)
225
+ notify_and_commit(state) do
226
+ if prepared_items.empty?
227
+ last ? state.buckets.pop : state.buckets.shift
228
+ else
229
+ bucket.items = prepared_items
230
+ end
231
+ state.size -= 1
232
+ track_remove(state, stored)
233
+ state.closed = true if state.sealed && state.size.zero? # rubocop:disable Style/ZeroLengthPredicate
234
+ end
235
+ tracked_value(state, stored)
236
+ end
237
+ return result unless EMPTY.equal?(result)
238
+ fallback&.call
239
+ end
240
+
241
+ def ensure_initializable!
242
+ raise "priority queue is already initialized" if @state
243
+ raise FrozenError, "can't modify frozen priority queue" if primitive_frozen?(self)
244
+ end
245
+
246
+ def commit_initialization(prepared)
247
+ INITIALIZATION_LOCK.synchronize do
248
+ raise "priority queue is already initialized" if @state
249
+ raise FrozenError, "can't modify frozen priority queue" if primitive_frozen?(self)
250
+
251
+ without_async_interrupts do
252
+ @state = prepared
253
+ primitive_freeze(self)
254
+ end
255
+ end
256
+ self
257
+ end
258
+
259
+ def initialized_state
260
+ @state || raise("uninitialized priority queue")
261
+ end
262
+
263
+ def normalize_capacity(capacity)
264
+ return nil if capacity.nil?
265
+ capacity = capacity.to_int unless primitive_is_a?(capacity, Integer)
266
+ raise TypeError, "capacity must be an Integer or nil" unless primitive_is_a?(capacity, Integer)
267
+ raise ArgumentError, "capacity must be positive or nil" unless capacity.positive?
268
+ capacity
269
+ end
270
+
271
+ def normalize_signal(signal)
272
+ return if signal.nil?
273
+ raise TypeError, "signal must respond to #broadcast" unless signal.respond_to?(:broadcast)
274
+ signal
275
+ end
276
+
277
+ def with_queue_operation(state)
278
+ current = Fiber.current
279
+ raise ThreadError, "deadlock; recursive priority queue access" if
280
+ primitive_identical?(state.operation_owner, current)
281
+
282
+ state.lock.synchronize do
283
+ without_async_interrupts { state.operation_owner = current }
284
+ yield
285
+ ensure
286
+ without_async_interrupts do
287
+ state.operation_owner = nil if primitive_identical?(state.operation_owner, current)
288
+ end
289
+ end
290
+ end
291
+
292
+ def read_endpoint(kind, last:, fallback:)
293
+ state = initialized_state
294
+ result = with_queue_operation(state) do
295
+ raise_closed if state.closed
296
+ bucket = last ? state.buckets.last : state.buckets.first
297
+ next EMPTY unless bucket
298
+ kind == :priority ? bucket.priority : tracked_value(state, bucket.items.first)
299
+ end
300
+ EMPTY.equal?(result) ? fallback&.call : result
301
+ end
302
+
303
+ def delete_value(priority, value, identity:, match: false)
304
+ state = initialized_state
305
+ with_queue_operation(state) do
306
+ raise_closed if state.closed
307
+ bucket_index, found = locate_priority(state.buckets, priority)
308
+ next false unless found
309
+
310
+ bucket = state.buckets[bucket_index]
311
+ item_index = if identity
312
+ bucket.items.index { primitive_identical?(tracked_value(state, it), value) }
313
+ elsif match
314
+ bucket.items.index { value === tracked_value(state, it) } # rubocop:disable Style/CaseEquality
315
+ else
316
+ bucket.items.index { tracked_value(state, it) == value }
317
+ end
318
+ next false unless item_index
319
+
320
+ removed = bucket.items[item_index]
321
+ prepared_items = bucket.items.dup
322
+ prepared_items.delete_at(item_index)
323
+ notify_and_commit(state) do
324
+ if prepared_items.empty?
325
+ state.buckets.delete_at(bucket_index)
326
+ else
327
+ bucket.items = prepared_items
328
+ end
329
+ state.size -= 1
330
+ track_remove(state, removed)
331
+ state.closed = true if state.sealed && state.size.zero? # rubocop:disable Style/ZeroLengthPredicate
332
+ end
333
+ true
334
+ end
335
+ end
336
+
337
+ def locate_priority(buckets, priority)
338
+ low = 0
339
+ high = buckets.length
340
+ while low < high
341
+ middle = (low + high) / 2
342
+ order = compare_priorities(priority, buckets[middle].priority)
343
+ return [middle, true] if order.zero?
344
+ order.negative? ? high = middle : low = middle + 1
345
+ end
346
+ [low, false]
347
+ end
348
+
349
+ def compare_priorities(left, right)
350
+ result = left <=> right
351
+ raise ArgumentError, "priority comparison failed" if result.nil?
352
+ # rb_cmpint calls #> and #< when <=> returns a non-Integer object.
353
+ return 1 if result > 0 # rubocop:disable Style/NumericPredicate
354
+ return -1 if result < 0 # rubocop:disable Style/NumericPredicate
355
+ 0
356
+ end
357
+
358
+ def notify_and_commit(state)
359
+ without_async_interrupts do
360
+ with_interruptible_callbacks { state.signal.broadcast } if state.signal
361
+ yield
362
+ end
363
+ end
364
+
365
+ def tracked_value(state, item) = state.track_age ? item.value : item
366
+
367
+ def track_push(state, item)
368
+ return unless state.track_age
369
+ state.tracked_items << item
370
+ state.generation += 1
371
+ end
372
+
373
+ def track_remove(state, item)
374
+ return unless state.track_age
375
+ state.tracked_items.delete(item)
376
+ state.generation += 1
377
+ end
378
+
379
+ def raise_closed
380
+ raise ::Farce::ClosedQueueError, "queue is closed"
381
+ end
382
+
383
+ def raise_sealed
384
+ raise ::Farce::SealedQueueError, "queue is sealed"
385
+ end
386
+ end
387
+ end
388
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/truffleruby/native/unsafe_tree_map"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ # Synchronized native-TruffleRuby map. Storage and ordered operations come
11
+ # from UnsafeTreeMap; this subclass adds coordination and guarded mutability.
12
+ class TreeMap < UnsafeTreeMap
13
+ def transaction_snapshot
14
+ state = initialized_state
15
+ entries, revision = with_map_operation(state, mutation: false) do
16
+ [state.entries.map { Entry.new(it.key, it.value) }, state.revision]
17
+ end
18
+ working = self.class.new
19
+ working.instance_variable_get(:@state).instance_variable_set(:@entries, entries)
20
+ PortableTransaction::TreeEntry.new(self, working, revision, state.lock, :@entries)
21
+ end
22
+
23
+ private
24
+
25
+ def synchronized? = true
26
+ def operation_lock = Lock.new
27
+ def ensure_mutation_still_allowed! = Internal::Freeze.check(self)
28
+
29
+ def with_map_operation(state, mutation:)
30
+ current = Fiber.current
31
+ raise ThreadError, "deadlock; recursive tree map access" if
32
+ primitive_identical?(state.operation_owner, current)
33
+
34
+ state.lock.synchronize do
35
+ ensure_mutation_still_allowed! if mutation
36
+ without_async_interrupts { state.operation_owner = current }
37
+ yield
38
+ ensure
39
+ without_async_interrupts do
40
+ state.operation_owner = nil if primitive_identical?(state.operation_owner, current)
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ MutableTreeMap = TreeMap
47
+
48
+ # No Ractors, no problems :)
49
+ ShareableTreeMap = TreeMap
50
+ end
51
+ end