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,189 @@
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
+ # Atom coordinates updates. The backend owns the weak slot and publishes
9
+ # changes, including writes whose requesting thread was interrupted.
10
+ class WeakAtomBase
11
+ TIMED_OUT = Object.new.freeze
12
+ private_constant :TIMED_OUT
13
+
14
+ def initialize(value = nil, compare_by_identity: false)
15
+ identity = BasicObject.instance_method(:equal?)
16
+ unless identity.bind_call(compare_by_identity, true) || identity.bind_call(compare_by_identity, false)
17
+ raise ArgumentError, "compare_by_identity must be a boolean"
18
+ end
19
+ validate_value(value)
20
+ @compare_by_identity = compare_by_identity
21
+ @lock = Atom.new
22
+ @changes = Atom.new(0)
23
+ @freeze_state = Flag.new(false)
24
+ initialize_storage(value)
25
+ end
26
+
27
+ def value = read_value
28
+ def compare_by_identity? = @compare_by_identity
29
+
30
+ def freeze
31
+ @freeze_state.set
32
+ self
33
+ end
34
+
35
+ def frozen? = @freeze_state.value
36
+
37
+ def value=(new_value)
38
+ store(new_value)
39
+ end
40
+
41
+ def get(timeout: nil, &fallback)
42
+ result = with_value(timeout) { read_value }
43
+ result.equal?(TIMED_OUT) ? fallback&.call : result
44
+ end
45
+
46
+ def store(new_value, timeout: nil, &fallback)
47
+ check_frozen!
48
+ validate_value(new_value)
49
+ result = with_value(timeout) do
50
+ check_frozen!
51
+ write_value(new_value)
52
+ new_value
53
+ end
54
+ result.equal?(TIMED_OUT) ? fallback&.call : result
55
+ end
56
+
57
+ def swap(new_value, timeout: nil, &fallback)
58
+ check_frozen!
59
+ validate_value(new_value)
60
+ result = with_value(timeout) do
61
+ check_frozen!
62
+ previous = read_value
63
+ write_value(new_value)
64
+ previous
65
+ end
66
+ result.equal?(TIMED_OUT) ? fallback&.call : result
67
+ end
68
+
69
+ def store_if_absent(timeout: nil)
70
+ raise LocalJumpError, "no block given" unless block_given?
71
+ check_frozen!
72
+ result = with_value(timeout) do
73
+ check_frozen!
74
+ current = read_value
75
+ next current unless current.nil?
76
+ replacement = yield
77
+ check_frozen!
78
+ validate_value(replacement)
79
+ write_value(replacement)
80
+ replacement
81
+ end
82
+ result.equal?(TIMED_OUT) ? nil : result
83
+ end
84
+
85
+ def compare_and_set(expected, replacement, timeout: nil)
86
+ check_frozen!
87
+ validate_value(expected)
88
+ validate_value(replacement)
89
+ result = with_value(timeout) do
90
+ matches = values_equal?(read_value, expected)
91
+ check_frozen!
92
+ next false unless matches
93
+ write_value(replacement)
94
+ true
95
+ end
96
+ !result.equal?(TIMED_OUT) && result
97
+ end
98
+
99
+ def update(timeout: nil)
100
+ raise LocalJumpError, "no block given" unless block_given?
101
+ check_frozen!
102
+ result = with_value(timeout) do
103
+ replacement = yield(read_value)
104
+ check_frozen!
105
+ validate_value(replacement)
106
+ write_value(replacement)
107
+ replacement
108
+ end
109
+ result.equal?(TIMED_OUT) ? nil : result
110
+ end
111
+
112
+ def upsert(initial, timeout: nil)
113
+ raise LocalJumpError, "no block given" unless block_given?
114
+ check_frozen!
115
+ validate_value(initial)
116
+ result = with_value(timeout) do
117
+ current = read_value
118
+ replacement = current.nil? ? initial : yield(current)
119
+ check_frozen!
120
+ validate_value(replacement)
121
+ write_value(replacement)
122
+ replacement
123
+ end
124
+ result.equal?(TIMED_OUT) ? nil : result
125
+ end
126
+
127
+ def wait_until_changed(expected, timeout: nil, &fallback)
128
+ validate_value(expected)
129
+ wait_for_value(expected, timeout, fallback, non_nil: false)
130
+ end
131
+
132
+ def wait_until_non_nil(timeout: nil, &fallback)
133
+ wait_for_value(nil, timeout, fallback, non_nil: true)
134
+ end
135
+
136
+ private
137
+
138
+ def check_frozen!
139
+ return unless frozen?
140
+
141
+ raise FrozenError.new("can't modify frozen #{self.class}", receiver: self)
142
+ end
143
+
144
+ def validate_value(_value); end
145
+
146
+ def with_value(timeout)
147
+ deadline = timeout_deadline(timeout)
148
+ result = TIMED_OUT
149
+ @lock.update(timeout: remaining_timeout(deadline)) do
150
+ result = yield
151
+ nil
152
+ end
153
+ result
154
+ end
155
+
156
+ def wait_for_value(expected, timeout, fallback, non_nil:)
157
+ deadline = timeout_deadline(timeout)
158
+ loop do
159
+ generation = @changes.value
160
+ current = read_value
161
+ return current if non_nil ? !current.nil? : !values_equal?(current, expected)
162
+ # Detect recursive waits without waiting for another owner's update.
163
+ @lock.get(timeout: 0)
164
+ return fallback&.call if remaining_timeout(deadline)&.zero?
165
+ @changes.wait_until_changed(generation, timeout: remaining_timeout(deadline))
166
+ end
167
+ end
168
+
169
+ def values_equal?(left, right)
170
+ return left == right unless compare_by_identity?
171
+ BasicObject.instance_method(:equal?).bind_call(left, right)
172
+ end
173
+
174
+ def timeout_deadline(timeout)
175
+ return if timeout.nil?
176
+ timeout = Float(timeout)
177
+ raise ArgumentError, "timeout must be finite and non-negative" unless timeout.finite? && !timeout.negative?
178
+ Clock.now + timeout
179
+ end
180
+
181
+ def remaining_timeout(deadline)
182
+ return unless deadline
183
+ remaining = deadline - Clock.now
184
+ remaining.negative? ? 0 : remaining
185
+ end
186
+ end
187
+ private_constant :WeakAtomBase
188
+ end
189
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/shared/unshared_weak_atom"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ class WeakAtom < UnsharedWeakAtom
11
+ private
12
+
13
+ def validate_value(value)
14
+ return if Farce::Ractor.shareable?(value)
15
+
16
+ raise Ractor::IsolationError, "value must be Ractor-shareable"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/shared/weak_map/reference"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ # The common cell holds its value directly. The index supplies key ownership.
11
+ # A WeakKeyMap index owns this cell and controls its collection lifetime.
12
+ class UnsharedWeakMapCell < UnsharedWeakMapLock
13
+ attr_reader :token
14
+
15
+ def initialize(key_reference)
16
+ super()
17
+ @token = Object.new
18
+ @key = key_reference
19
+ @value = nil
20
+ @present = @retired = false
21
+ @changes = nil
22
+ end
23
+
24
+ def lookup_key
25
+ @mutex.synchronize do
26
+ return [false, nil] if @retired
27
+ alive, key = @key.read
28
+ return [false, nil] unless alive
29
+ [@reserved || !@present || read_value.first, key]
30
+ end
31
+ end
32
+
33
+ def state
34
+ @mutex.synchronize do
35
+ return [:retired, false, nil] if @retired
36
+ return [:dead, false, nil] unless @key.read.first
37
+ return [:ok, false, nil] unless @present
38
+ alive, value = read_value
39
+ [alive ? :ok : :dead, alive, value]
40
+ end
41
+ end
42
+
43
+ def present? = @mutex.synchronize { @present }
44
+ def retired? = @mutex.synchronize { @retired }
45
+
46
+ def store(value)
47
+ @mutex.synchronize do
48
+ return false if @retired || !@key.read.first
49
+ write_value(value)
50
+ @present = true
51
+ @changes&.broadcast
52
+ true
53
+ end
54
+ end
55
+
56
+ def retire = retire_state(force: true).first
57
+ def retire_if_dead = retire_state(force: false)
58
+
59
+ def change_generation
60
+ @mutex.synchronize { (@changes ||= Signal.new).generation }
61
+ end
62
+
63
+ def wait_for_change?(observed, deadline)
64
+ timeout = deadline - Clock.now if deadline
65
+ return false if timeout && !timeout.positive?
66
+ !!@changes.wait(observed, timeout:) { false }
67
+ end
68
+
69
+ private
70
+
71
+ def unavailable? = @retired
72
+ def read_value = [true, @value]
73
+ def write_value(value) = @value = value
74
+
75
+ def retire_state(force:)
76
+ @mutex.synchronize do
77
+ return [false, false, nil] if @retired || (!force && @reserved)
78
+ alive, key = @key.read
79
+ return [false, false, nil] if !force && alive && (!@present || read_value.first)
80
+ @retired = true
81
+ @present = false
82
+ @key = @value = nil
83
+ @changes&.broadcast
84
+ @signal&.broadcast
85
+ [true, alive, key]
86
+ end
87
+ end
88
+ end
89
+ private_constant :UnsharedWeakMapCell
90
+
91
+ class UnsharedWeakValueMapCell < UnsharedWeakMapCell
92
+ private
93
+
94
+ def read_value = @value.read
95
+ def write_value(value) = @value = UnsharedWeakMapWeakReference.for(value)
96
+ end
97
+ private_constant :UnsharedWeakValueMapCell
98
+ end
99
+ end
@@ -0,0 +1,249 @@
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
+ # Shared coordination for indexes. Reference ownership belongs to the
9
+ # concrete index and cell classes, never to flags in this class.
10
+ class UnsharedWeakMapIndex
11
+ attr_reader :change_signal
12
+
13
+ def initialize
14
+ @lock = UnsharedWeakMapLock.new
15
+ @registry_mutex = Mutex.new
16
+ @change_signal = Signal.new
17
+ @sweep_cursor = 0
18
+ @iteration_epoch = 0
19
+ @registry_holes = 0
20
+ reset
21
+ end
22
+
23
+ def resolve(key, deadline: nil, create: false)
24
+ completed, result = @lock.synchronize(deadline) do
25
+ data = data_for(key)
26
+ indexed_key = index_key(key)
27
+ entry = data[indexed_key]
28
+ if entry
29
+ retired, = entry.retire_if_dead
30
+ if retired || entry.retired?
31
+ data.delete(indexed_key)
32
+ forget(entry)
33
+ entry = nil
34
+ end
35
+ end
36
+ created = false
37
+ if !entry && create
38
+ begin
39
+ entry = yield(key_reference(key))
40
+ data[indexed_key] = entry
41
+ register(entry)
42
+ created = true
43
+ @change_signal.broadcast
44
+ ensure
45
+ unless created
46
+ entry&.retire
47
+ entry&.release
48
+ end
49
+ end
50
+ end
51
+ [entry, created]
52
+ end
53
+ completed ? result : [nil, :timed_out]
54
+ end
55
+
56
+ def remove(key, entry)
57
+ @lock.synchronize do
58
+ unlink(entry, key)
59
+ forget(entry)
60
+ end
61
+ @change_signal.broadcast
62
+ end
63
+
64
+ def clear
65
+ _, entries = @lock.synchronize do
66
+ entries = snapshot
67
+ reset
68
+ entries
69
+ end
70
+ entries.each(&:retire)
71
+ @change_signal.broadcast
72
+ end
73
+
74
+ def sweep(entries)
75
+ stale = entries.reject { it.lookup_key.first }
76
+ return if stale.empty?
77
+ @lock.synchronize { stale.each { sweep_entry(it) } }
78
+ end
79
+
80
+ def sweep_one
81
+ entry = @registry_mutex.synchronize do
82
+ next if @entries.empty?
83
+ @sweep_cursor %= @entries.size
84
+ @entries[@sweep_cursor].tap { @sweep_cursor += 1 }
85
+ end
86
+ return unless entry && !entry.lookup_key.first
87
+ @lock.try_synchronize { sweep_entry(entry) }
88
+ end
89
+
90
+ def snapshot = @registry_mutex.synchronize { @entries.compact }
91
+
92
+ def live_cursor
93
+ @registry_mutex.synchronize do
94
+ [registry_enumerator, @iteration_epoch]
95
+ end
96
+ end
97
+
98
+ def next_live(cursor)
99
+ @registry_mutex.synchronize do
100
+ raise "map structurally changed during live iteration" if cursor[1] != @iteration_epoch
101
+ while (entry = cursor[0].next).nil?
102
+ # Deletion leaves a hole while an array cursor is active.
103
+ end
104
+ entry
105
+ end
106
+ end
107
+
108
+ def close_cursor(cursor)
109
+ cursor[0] = nil
110
+ end
111
+
112
+ private
113
+
114
+ def data_for(_key) = @data
115
+ def index_key(key) = key
116
+ def key_reference(key) = UnsharedWeakMapReference.new(key)
117
+ def registry_enumerator = @entries.to_enum(:each)
118
+
119
+ def register(entry)
120
+ @registry_mutex.synchronize do
121
+ @iteration_epoch += 1
122
+ @entries << entry
123
+ end
124
+ end
125
+
126
+ def forget(entry)
127
+ @registry_mutex.synchronize do
128
+ if (index = @entries.index(entry))
129
+ @entries[index] = nil
130
+ @registry_holes += 1
131
+ if @registry_holes > @entries.size / 4
132
+ # Existing cursors keep their old array. Retired cells release
133
+ # their keys and values, so abandoning a cursor retains no
134
+ # registration in the map and requires no finalizer.
135
+ @entries = @entries.compact
136
+ @registry_holes = 0
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ def sweep_entry(entry)
143
+ retired, alive, key = entry.retire_if_dead
144
+ return unless retired
145
+ unlink(entry, key) if alive
146
+ forget(entry)
147
+ @change_signal.broadcast
148
+ end
149
+
150
+ def unlink(entry, key)
151
+ data = data_for(key)
152
+ indexed_key = index_key(key)
153
+ data.delete(indexed_key) if data[indexed_key].equal?(entry)
154
+ end
155
+ end
156
+ private_constant :UnsharedWeakMapIndex
157
+
158
+ # WeakKeyMap is the only owner of heap-keyed cells. The enumerable registry
159
+ # is weak and cannot prolong a cell's lifetime. Immediate keys need a Hash.
160
+ # Comparison and cleanup follow the primitive. JRuby currently uses ==
161
+ # instead of eql?, and JVM runtimes defer stale value cleanup until access.
162
+ class UnsharedWeakKeyMapIndex < UnsharedWeakMapIndex
163
+ def snapshot = @registry_mutex.synchronize { @entries.values }
164
+
165
+ def sweep_one
166
+ return unless @entries.respond_to?(:sweep_one)
167
+ @registry_mutex.synchronize { @entries.sweep_one }
168
+ end
169
+
170
+ private
171
+
172
+ def reset
173
+ @data = ObjectSpace::WeakKeyMap.new
174
+ @immediate = {}
175
+ @registry_mutex.synchronize do
176
+ @entries = if Internal.const_defined?(:ConcurrentWeakRegistry, false)
177
+ ConcurrentWeakRegistry.new
178
+ else
179
+ ObjectSpace::WeakMap.new
180
+ end
181
+ @iteration_epoch += 1
182
+ end
183
+ end
184
+
185
+ def data_for(key) = Internal.garbage_collectable?(key) ? @data : @immediate
186
+ def key_reference(key) = UnsharedWeakMapWeakReference.for(key)
187
+ def registry_enumerator = @entries.to_enum(:each_value)
188
+
189
+ def register(entry)
190
+ @registry_mutex.synchronize do
191
+ @iteration_epoch += 1
192
+ @entries[entry.token] = entry
193
+ end
194
+ end
195
+
196
+ def forget(entry) = @registry_mutex.synchronize { @entries.delete(entry.token) }
197
+ end
198
+ private_constant :UnsharedWeakKeyMapIndex
199
+
200
+ # WeakMap has weak values too, so this index must retain its cells. Its
201
+ # strong side is reclaimed by housekeeping after an identity key disappears.
202
+ class UnsharedWeakIdentityMapIndex < UnsharedWeakMapIndex
203
+ private
204
+
205
+ def reset
206
+ @data = ObjectSpace::WeakMap.new
207
+ @registry_mutex.synchronize do
208
+ @entries = []
209
+ @registry_holes = 0
210
+ @iteration_epoch += 1
211
+ end
212
+ end
213
+
214
+ def key_reference(key) = UnsharedWeakMapWeakReference.for(key)
215
+ end
216
+ private_constant :UnsharedWeakIdentityMapIndex
217
+
218
+ class UnsharedStrongKeyMapIndex < UnsharedWeakMapIndex
219
+ private
220
+
221
+ def reset
222
+ @data = {}
223
+ @registry_mutex.synchronize do
224
+ @entries = []
225
+ @registry_holes = 0
226
+ @iteration_epoch += 1
227
+ end
228
+ end
229
+ end
230
+ private_constant :UnsharedStrongKeyMapIndex
231
+
232
+ class UnsharedStrongIdentityMapIndex < UnsharedStrongKeyMapIndex
233
+ # Ruby numeric identity can differ from a JVM object's identity.
234
+ class Key
235
+ attr_reader :value
236
+
237
+ def initialize(value) = @value = value
238
+ def hash = BasicObject.instance_method(:__id__).bind_call(value)
239
+ def eql?(other) = other.is_a?(Key) && BasicObject.instance_method(:equal?).bind_call(value, other.value)
240
+ end
241
+ private_constant :Key
242
+
243
+ private
244
+
245
+ def index_key(key) = Key.new(key)
246
+ end
247
+ private_constant :UnsharedStrongIdentityMapIndex
248
+ end
249
+ end
@@ -0,0 +1,80 @@
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
+ # A per-key reservation. User code runs without holding the state mutex.
9
+ # The same lock protects creation in a key index, as in Storage::ThreadSafe.
10
+ class UnsharedWeakMapLock
11
+ def initialize
12
+ @mutex = Mutex.new
13
+ @reserved = false
14
+ @owner_fiber = nil
15
+ @owner_thread = nil
16
+ @signal = nil
17
+ end
18
+
19
+ def reserve(deadline)
20
+ while true
21
+ signal, observed = @mutex.synchronize do
22
+ return :retired if unavailable?
23
+ unless @reserved
24
+ @reserved = true
25
+ @owner_fiber = Fiber.current
26
+ @owner_thread = Internal.storage_thread(Thread.current)
27
+ return :acquired
28
+ end
29
+ reject_recursive_wait!
30
+ @signal ||= Signal.new
31
+ [@signal, @signal.generation]
32
+ end
33
+ return :timed_out unless ReservationWaiting.wait(signal, observed, deadline)
34
+ end
35
+ end
36
+
37
+ def release
38
+ signal = @mutex.synchronize do
39
+ @reserved = false
40
+ @owner_fiber = @owner_thread = nil
41
+ @signal
42
+ end
43
+ signal&.broadcast
44
+ end
45
+
46
+ def synchronize(deadline = nil)
47
+ acquired = reserve(deadline) == :acquired
48
+ acquired ? [true, yield] : [false, nil]
49
+ ensure
50
+ release if acquired
51
+ end
52
+
53
+ def try_synchronize
54
+ acquired = @mutex.synchronize do
55
+ next false if @reserved
56
+ @reserved = true
57
+ @owner_fiber = Fiber.current
58
+ @owner_thread = Internal.storage_thread(Thread.current)
59
+ true
60
+ end
61
+ acquired ? [true, yield] : [false, nil]
62
+ ensure
63
+ release if acquired
64
+ end
65
+
66
+ private
67
+
68
+ def unavailable? = false
69
+
70
+ def reject_recursive_wait!
71
+ raise ThreadError, "deadlock; recursive weak-map access during an update" if @owner_fiber.equal?(Fiber.current)
72
+ scheduler = Fiber.scheduler if Fiber.respond_to?(:scheduler)
73
+ return unless @owner_thread.equal?(Internal.storage_thread(Thread.current)) && !scheduler
74
+
75
+ raise ThreadError, "deadlock; weak-map update is owned by another unscheduled fiber"
76
+ end
77
+ end
78
+ private_constant :UnsharedWeakMapLock
79
+ end
80
+ end
@@ -0,0 +1,33 @@
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 UnsharedWeakMapReference
9
+ def initialize(value) = @value = value
10
+ def read = [true, @value]
11
+ end
12
+ private_constant :UnsharedWeakMapReference
13
+
14
+ # A weak value slot also supplies reverse key lookup for enumeration.
15
+ class UnsharedWeakMapWeakReference
16
+ def self.for(value)
17
+ Internal.garbage_collectable?(value) ? new(value) : UnsharedWeakMapReference.new(value)
18
+ end
19
+
20
+ def initialize(value)
21
+ @token = Object.new
22
+ @data = ObjectSpace::WeakMap.new
23
+ @data[@token] = value
24
+ end
25
+
26
+ def read
27
+ value = @data[@token]
28
+ [!value.nil?, value]
29
+ end
30
+ end
31
+ private_constant :UnsharedWeakMapWeakReference
32
+ end
33
+ end