farce 0.0.1.alpha2-x86_64-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,342 @@
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
+ # Coordinates ownership and lifecycle for one leased resource.
9
+ class LeaseState
10
+ OWNED_RESOURCES = Object.new.freeze
11
+ SCOPE_MANAGED_RESOURCES = Object.new.freeze
12
+ AVAILABLE = :available
13
+ EXPLICIT = :explicit
14
+ BLOCK = :block
15
+ RETIRED = :retired
16
+ private_constant :OWNED_RESOURCES, :SCOPE_MANAGED_RESOURCES,
17
+ :AVAILABLE, :EXPLICIT, :BLOCK, :RETIRED
18
+
19
+ def initialize(resource)
20
+ validate_resource!(resource)
21
+ initialize_state
22
+ initialize_resource(resource)
23
+ end
24
+
25
+ def available? = state == AVAILABLE && !@lock.locked?
26
+ def checked_out? = !retired? && @lock.locked?
27
+ def owned? = !retired? && @lock.owned?
28
+ def retired? = state == RETIRED
29
+ def explicitly_owned? = owned? && state == EXPLICIT
30
+
31
+ # Return the resource held by the current Fiber.
32
+ # @raise [Farce::OwnershipError] unless the current Fiber owns the checkout
33
+ def owned_resource
34
+ raise OwnershipError, "the current Fiber does not own the checkout" unless @lock.owned?
35
+
36
+ owned_resources.fetch(self)
37
+ end
38
+
39
+ # Replace the resource held by an explicit checkout without ending it.
40
+ # @raise [Farce::OwnershipError] unless the current Fiber owns an explicit checkout
41
+ def replace_owned_resource(resource)
42
+ unless @lock.owned? && state == EXPLICIT
43
+ raise OwnershipError, "the current Fiber does not own an explicit checkout"
44
+ end
45
+
46
+ validate_resource!(resource)
47
+ owned_resources[self] = resource
48
+ self
49
+ end
50
+
51
+ # Acquire explicitly and complete a caller-provided ownership handoff before interrupts resume.
52
+ def checkout_with_handoff(timeout: nil)
53
+ resource = nil
54
+ begin
55
+ Thread.handle_interrupt(INTERRUPT_MASK) do
56
+ resource = wait_for_resource(timeout, EXPLICIT)
57
+ yield resource
58
+ end
59
+ rescue Exception # rubocop:disable Lint/RescueException
60
+ rollback_acquisition(resource) if resource && @lock.owned? && state == EXPLICIT
61
+ raise
62
+ end
63
+ resource
64
+ end
65
+
66
+ # Attempt an explicit checkout and complete an ownership handoff before interrupts resume.
67
+ def try_checkout_with_handoff
68
+ resource = nil
69
+ begin
70
+ Thread.handle_interrupt(INTERRUPT_MASK) do
71
+ resource = try_acquire(EXPLICIT)
72
+ yield resource if resource
73
+ end
74
+ rescue Exception # rubocop:disable Lint/RescueException
75
+ rollback_acquisition(resource) if resource && @lock.owned? && state == EXPLICIT
76
+ raise
77
+ end
78
+ resource
79
+ end
80
+
81
+ # Mark an explicit checkout as owned by an automatic cleanup scope.
82
+ def mark_scope_managed
83
+ unless @lock.owned? && state == EXPLICIT
84
+ raise OwnershipError, "the current Fiber does not own an explicit checkout"
85
+ end
86
+
87
+ scope_managed_resources[self] = true
88
+ self
89
+ end
90
+
91
+ def scope_managed? = Storage.fiber[SCOPE_MANAGED_RESOURCES, :strong]&.key?(self) || false
92
+
93
+ # Return a checkout through its automatic cleanup scope.
94
+ def checkin_scope(resource)
95
+ checkin_resource(resource, scope: true)
96
+ end
97
+
98
+ def checkout(timeout: nil, &block)
99
+ return wait_for_block(timeout, block) if block
100
+
101
+ explicit_checkout { wait_for_resource(timeout, EXPLICIT) }
102
+ end
103
+
104
+ def try_checkout(&block)
105
+ if block
106
+ outcome = try_acquire_block(block)
107
+ return outcome.first if outcome
108
+ return
109
+ end
110
+
111
+ explicit_checkout { try_acquire(EXPLICIT) }
112
+ end
113
+
114
+ def checkin(resource)
115
+ checkin_resource(resource, scope: false)
116
+ end
117
+
118
+ def checkin_resource(resource, scope:)
119
+ raise RetiredLeaseError, "lease has been retired" if retired?
120
+ unless @lock.owned? && state == EXPLICIT
121
+ raise OwnershipError, "the current Fiber does not own an explicit checkout"
122
+ end
123
+ raise OwnershipError, "the checkout belongs to an automatic lease scope" if scope_managed? && !scope
124
+
125
+ validate_resource!(resource)
126
+ Thread.handle_interrupt(INTERRUPT_MASK) do
127
+ return_resource(resource)
128
+ unregister_owned_resource
129
+ release
130
+ end
131
+ self
132
+ end
133
+
134
+ def retire
135
+ return self if retired?
136
+ raise OwnershipError, "the current Fiber does not own the checkout" unless @lock.owned?
137
+
138
+ Thread.handle_interrupt(INTERRUPT_MASK) do
139
+ @state.store(RETIRED)
140
+ unregister_owned_resource
141
+ @owner_thread_id.store(0)
142
+ @lock.unlock
143
+ @signal.broadcast
144
+ end
145
+ self
146
+ end
147
+
148
+ private
149
+
150
+ def wait_for_resource(timeout, kind)
151
+ deadline = timeout_deadline(timeout)
152
+ resource = nil
153
+
154
+ loop do
155
+ observed = @signal.generation
156
+ resource = try_acquire(kind)
157
+ return resource if resource
158
+
159
+ remaining = deadline - Clock.now if deadline
160
+ raise TimeoutError, "lease checkout timed out" if remaining && !remaining.positive?
161
+ reject_unscheduled_fiber_wait!
162
+ interval = wait_interval(remaining)
163
+ changed = Thread.handle_interrupt(Exception => :immediate) do
164
+ @signal.wait(observed, timeout: interval)
165
+ end
166
+ next if changed || interval != remaining
167
+
168
+ raise TimeoutError, "lease checkout timed out"
169
+ end
170
+ rescue Exception # rubocop:disable Lint/RescueException
171
+ rollback_acquisition(resource) if resource && @lock.owned? && state == kind
172
+ raise
173
+ end
174
+
175
+ def wait_for_block(timeout, block)
176
+ deadline = timeout_deadline(timeout)
177
+
178
+ loop do
179
+ observed = @signal.generation
180
+ outcome = try_acquire_block(block)
181
+ return outcome.first if outcome
182
+
183
+ remaining = deadline - Clock.now if deadline
184
+ raise TimeoutError, "lease checkout timed out" if remaining && !remaining.positive?
185
+ reject_unscheduled_fiber_wait!
186
+ interval = wait_interval(remaining)
187
+ changed = Thread.handle_interrupt(Exception => :immediate) do
188
+ @signal.wait(observed, timeout: interval)
189
+ end
190
+ next if changed || interval != remaining
191
+
192
+ raise TimeoutError, "lease checkout timed out"
193
+ end
194
+ end
195
+
196
+ def checkin_block(resource)
197
+ return if retired?
198
+ raise OwnershipError, "the current Fiber does not own this block checkout" unless
199
+ @lock.owned? && state == BLOCK
200
+
201
+ Thread.handle_interrupt(INTERRUPT_MASK) do
202
+ return_resource(resource)
203
+ unregister_owned_resource
204
+ release
205
+ end
206
+ end
207
+
208
+ def initialize_state
209
+ @lock = Lock.new
210
+ @state = Atom.new(AVAILABLE)
211
+ @signal = Signal.new
212
+ @owner_thread_id = Atom.new(0)
213
+ end
214
+
215
+ def state = @state.value
216
+
217
+ def try_acquire_block(block)
218
+ raise RetiredLeaseError, "lease has been retired" if retired?
219
+ raise ThreadError, "deadlock; recursive lease checkout" if @lock.owned?
220
+
221
+ acquired = false
222
+ resource = nil
223
+ Thread.handle_interrupt(INTERRUPT_MASK) do
224
+ acquired = @lock.try_lock
225
+ return unless acquired
226
+
227
+ begin
228
+ raise RetiredLeaseError, "lease has been retired" if retired?
229
+ @owner_thread_id.store(Thread.current.object_id)
230
+ @state.store(BLOCK)
231
+ resource = take_resource
232
+ register_owned_resource(resource)
233
+ [Thread.handle_interrupt(Exception => :immediate) { block.call(resource) }]
234
+ ensure
235
+ if resource
236
+ checkin_block(resource) if @lock.owned? && state == BLOCK
237
+ elsif acquired
238
+ rollback_acquisition(resource)
239
+ end
240
+ end
241
+ end
242
+ end
243
+
244
+ def explicit_checkout
245
+ resource = nil
246
+ begin
247
+ Thread.handle_interrupt(INTERRUPT_MASK) { resource = yield }
248
+ rescue Exception # rubocop:disable Lint/RescueException
249
+ rollback_acquisition(resource) if resource && @lock.owned? && state == EXPLICIT
250
+ raise
251
+ end
252
+ resource
253
+ end
254
+
255
+ def try_acquire(kind)
256
+ raise RetiredLeaseError, "lease has been retired" if retired?
257
+ raise ThreadError, "deadlock; recursive lease checkout" if @lock.owned?
258
+
259
+ acquired = false
260
+ resource = nil
261
+ begin
262
+ Thread.handle_interrupt(INTERRUPT_MASK) do
263
+ acquired = @lock.try_lock
264
+ return unless acquired
265
+
266
+ raise RetiredLeaseError, "lease has been retired" if retired?
267
+ @owner_thread_id.store(Thread.current.object_id)
268
+ @state.store(kind)
269
+ resource = take_resource
270
+ register_owned_resource(resource)
271
+ end
272
+ rescue Exception # rubocop:disable Lint/RescueException
273
+ rollback_acquisition(resource) if acquired
274
+ raise
275
+ end
276
+ resource
277
+ end
278
+
279
+ def release
280
+ @state.store(AVAILABLE)
281
+ @owner_thread_id.store(0)
282
+ @lock.unlock
283
+ @signal.broadcast
284
+ end
285
+
286
+ def rollback_acquisition(resource)
287
+ Thread.handle_interrupt(INTERRUPT_MASK) do
288
+ return_resource(resource) if resource
289
+ unregister_owned_resource
290
+ @state.store(AVAILABLE) unless retired?
291
+ @owner_thread_id.store(0)
292
+ @lock.unlock if @lock.owned?
293
+ @signal.broadcast
294
+ end
295
+ end
296
+
297
+ def reject_unscheduled_fiber_wait!
298
+ return unless @lock.locked? && @owner_thread_id.value == Thread.current.object_id
299
+ return if Fiber.respond_to?(:scheduler) && Fiber.scheduler
300
+
301
+ raise ThreadError, "deadlock; lease is owned by another unscheduled Fiber on the same thread"
302
+ end
303
+
304
+ def wait_interval(remaining)
305
+ LeaseWaiting.wait_interval(remaining)
306
+ end
307
+
308
+ def owned_resources
309
+ Storage.fiber.store_if_absent(OWNED_RESOURCES, mode: :strong) { {}.compare_by_identity }
310
+ end
311
+
312
+ def register_owned_resource(resource)
313
+ owned_resources[self] = resource
314
+ end
315
+
316
+ def unregister_owned_resource
317
+ Storage.fiber[OWNED_RESOURCES, :strong]&.delete(self)
318
+ Storage.fiber[SCOPE_MANAGED_RESOURCES, :strong]&.delete(self)
319
+ end
320
+
321
+ def scope_managed_resources
322
+ Storage.fiber.store_if_absent(SCOPE_MANAGED_RESOURCES, mode: :strong) { {}.compare_by_identity }
323
+ end
324
+
325
+ def timeout_deadline(timeout)
326
+ return if timeout.nil?
327
+
328
+ timeout = Float(timeout)
329
+ unless timeout.finite? && !timeout.negative?
330
+ raise ArgumentError, "timeout must be a finite, non-negative number or nil"
331
+ end
332
+ Clock.now + timeout
333
+ end
334
+
335
+ def validate_resource!(resource)
336
+ return unless nil.equal?(resource) || true.equal?(resource) || false.equal?(resource)
337
+
338
+ raise ArgumentError, "lease resource cannot be nil or boolean"
339
+ end
340
+ end
341
+ end
342
+ end
@@ -0,0 +1,13 @@
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
+ # Selects how long a Lease waits for one signal notification.
9
+ module LeaseWaiting
10
+ def self.wait_interval(remaining) = remaining
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal # :nodoc: all
7
+ # Shared mode metadata and deletion probes. Reads and writes are specialized
8
+ # in each public class to avoid forwarding overhead on the hot path.
9
+ module ManagedQueue
10
+ DeleteProbe = Data.define(:value, :compare_by_identity, :manager) do
11
+ def ===(stored) = manager.same_value?(stored, value, identity: compare_by_identity)
12
+ end
13
+ private_constant :DeleteProbe
14
+
15
+ def mode = @manager.mode
16
+
17
+ private
18
+
19
+ def delete_from_storage(priority, value, compare_by_identity:)
20
+ comparison_mode = compare_by_identity ? :local : :copy
21
+ value = @manager.wrap(value, mode: comparison_mode)
22
+ @queue.delete_match(priority, DeleteProbe.new(value, compare_by_identity, @manager))
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # @!visibility private
7
+ module Internal # :nodoc: all
8
+ module MapValueModes
9
+ NIL_VALUE = Object.new.freeze
10
+ TIMED_OUT = Object.new.freeze
11
+ CANCEL_UPDATE = Object.new.freeze
12
+ private_constant :NIL_VALUE, :TIMED_OUT, :CANCEL_UPDATE
13
+
14
+ # @!macro modes
15
+ # @param initial_mapping [Hash, Farce::Abstract::Map, #each, nil] initial entries with shareable keys
16
+ # @param mode [Symbol] the default value transfer mode
17
+ # @!macro key_normalization
18
+ # @param compare_by_identity [Boolean] the default comparison mode for keys and values
19
+ # @param compare_keys_by_identity [Boolean] whether keys are compared by identity
20
+ # @param compare_values_by_identity [Boolean] whether values are compared by identity
21
+ def initialize(initial_mapping = nil, mode: :copy, normalize_keys: nil, compare_by_identity: false,
22
+ compare_keys_by_identity: compare_by_identity, compare_values_by_identity: compare_by_identity)
23
+ initial_mapping = convert_entries(initial_mapping)
24
+
25
+ identity = BasicObject.instance_method(:equal?)
26
+ valid_comparison = identity.bind_call(compare_values_by_identity, true) ||
27
+ identity.bind_call(compare_values_by_identity, false)
28
+
29
+ raise ArgumentError, "compare_values_by_identity must be a boolean" unless valid_comparison
30
+ @compare_values_by_identity = compare_values_by_identity
31
+
32
+ @manager = new_mode_manager(mode:)
33
+ @map = new_map(compare_by_identity:, compare_keys_by_identity:, compare_values_by_identity: true)
34
+ KeyNormalizer.prepare_concurrent(@map)
35
+
36
+ restoring = KeyNormalizer.restoration?(normalize_keys)
37
+ normalizer = KeyNormalizer.build(normalize_keys, shareable: true)
38
+ KeyNormalizer.install_concurrent(self, normalizer) unless restoring
39
+
40
+ initial_mapping&.each { |key, value| self[key] = value }
41
+ KeyNormalizer.install_concurrent(self, normalizer) if restoring
42
+ super()
43
+ end
44
+
45
+ # Build a wrapper that preserves this object's value modes.
46
+ def transaction_wrapper(transaction)
47
+ Transaction::Map.new(transaction, self, @map, manager: @manager, nil_value: NIL_VALUE)
48
+ end
49
+
50
+ # The default transfer mode for values.
51
+ # @return [Symbol]
52
+ def mode = @manager.mode
53
+ def compare_values_by_identity? = @compare_values_by_identity
54
+ def shareable_keys? = true
55
+ def shareable_values? = true
56
+ def [](key) = unwrap_value(@map[key])
57
+
58
+ def []=(key, value)
59
+ key = @map.prepare_mutation_key(key)
60
+ @map.store_prepared(key, wrap_value(value))
61
+ value
62
+ end
63
+
64
+ def fetch(*arguments)
65
+ unless arguments.length.between?(1, 2)
66
+ raise ArgumentError, "wrong number of arguments (given #{arguments.length}, expected 1..2)"
67
+ end
68
+ key, default = arguments
69
+ warn "block supersedes default value argument", uplevel: 1 if block_given? && arguments.length == 2
70
+ value = @map.fetch(key) do
71
+ return yield(key) if block_given?
72
+ return default if arguments.length == 2
73
+ raise KeyError.new("key not found: #{key.inspect}", receiver: self, key: key)
74
+ end
75
+ unwrap_value(value)
76
+ end
77
+
78
+ def get(key, timeout: nil, &) = unwrap_result(@map.get(key, timeout:) { TIMED_OUT }, &)
79
+
80
+ # (see Abstract::ConcurrentMap#store)
81
+ # @param mode [Symbol, nil] the value transfer mode, or nil to use the default
82
+ def store(key, value, mode: nil, timeout: nil, &)
83
+ key = @map.prepare_mutation_key(key)
84
+ unwrap_result(@map.store_prepared(key, wrap_value(value, mode:), timeout:) { TIMED_OUT }, &)
85
+ end
86
+
87
+ # (see Abstract::ConcurrentMap#swap)
88
+ # @param mode [Symbol, nil] the replacement's transfer mode, or nil to use the default
89
+ def swap(key, replacement, mode: nil, timeout: nil, &)
90
+ key = @map.prepare_mutation_key(key)
91
+ unwrap_result(@map.swap_prepared(key, wrap_value(replacement, mode:), timeout:) { TIMED_OUT }, &)
92
+ end
93
+
94
+ # (see Abstract::ConcurrentMap#store_if_absent)
95
+ # @param mode [Symbol, nil] the result's transfer mode, or nil to use the default
96
+ def store_if_absent(key, mode: nil, timeout: nil)
97
+ raise LocalJumpError, "no block given" unless block_given?
98
+ @map.check_mutation
99
+ unwrap_value(@map.store_if_absent(key, timeout:) do
100
+ value = yield
101
+ @map.check_mutation
102
+ wrap_value(value, mode:)
103
+ end)
104
+ end
105
+
106
+ # (see Abstract::ConcurrentMap#update)
107
+ # @param mode [Symbol, nil] the result's transfer mode, or nil to use the default
108
+ def update(key, mode: nil, timeout: nil)
109
+ raise LocalJumpError, "no block given" unless block_given?
110
+ @map.check_mutation
111
+ unwrap_value(@map.update(key, timeout:) do |current|
112
+ value = yield(unwrap_value(current))
113
+ @map.check_mutation
114
+ wrap_value(value, mode:)
115
+ end)
116
+ end
117
+
118
+ # (see Abstract::ConcurrentMap#upsert)
119
+ # @param mode [Symbol, nil] the value transfer mode, or nil to use the default
120
+ def upsert(key, initial, mode: nil, timeout: nil)
121
+ raise LocalJumpError, "no block given" unless block_given?
122
+ @map.check_mutation
123
+ unwrap_value(@map.update(key, timeout:) do |current|
124
+ value = nil.equal?(current) ? initial : yield(unwrap_value(current))
125
+ @map.check_mutation
126
+ wrap_value(value, mode:)
127
+ end)
128
+ end
129
+
130
+ # (see Abstract::ConcurrentMap#compare_and_set)
131
+ # @param mode [Symbol, nil] the replacement's transfer mode, or nil to use the default
132
+ def compare_and_set(key, expected, replacement, mode: nil, timeout: nil)
133
+ key = @map.prepare_mutation_key(key)
134
+ expected = wrap_comparison(expected)
135
+ catch(CANCEL_UPDATE) do
136
+ result = @map.update_prepared(key, timeout:) do |current|
137
+ # Abort the update instead of inserting a value for a missing key.
138
+ throw CANCEL_UPDATE, false if nil.equal?(current) || !values_equal?(current, expected)
139
+ @map.check_mutation
140
+ wrap_value(replacement, mode:)
141
+ end
142
+ !nil.equal?(result)
143
+ end
144
+ end
145
+
146
+ def wait_until_changed(key, expected, timeout: nil, &)
147
+ prepared_key = @map.normalize_external_key(key)
148
+ expected = wrap_comparison(expected)
149
+ deadline = Internal.timeout_deadline(timeout)
150
+ loop do
151
+ current = @map.get_prepared(prepared_key, timeout: Internal.remaining_timeout(deadline)) { TIMED_OUT }
152
+ return unwrap_result(current, &) if TIMED_OUT.equal?(current)
153
+ return unwrap_value(current) unless values_equal?(nil.equal?(current) ? NIL_VALUE : current, expected)
154
+ result = @map.wait_until_changed_prepared(
155
+ prepared_key,
156
+ current,
157
+ timeout: Internal.remaining_timeout(deadline),
158
+ ) { TIMED_OUT }
159
+ return unwrap_result(result, &) if TIMED_OUT.equal?(result)
160
+ end
161
+ end
162
+
163
+ def wait_until_non_nil(key, timeout: nil, &) = wait_until_changed(key, nil, timeout:, &)
164
+ def delete(key) = unwrap_value(@map.delete(key))
165
+
166
+ def each
167
+ return enum_for(__method__) { size } unless block_given?
168
+ @map.each { |key, value| yield [key, unwrap_value(value)] }
169
+ self
170
+ end
171
+ alias each_pair each
172
+
173
+ def each_live
174
+ return enum_for(__method__) { size } unless block_given?
175
+ @map.each_live { |key, value| yield [key, unwrap_value(value)] }
176
+ self
177
+ end
178
+
179
+ def each_value
180
+ return enum_for(__method__) { size } unless block_given?
181
+ @map.each_value { |value| yield unwrap_value(value) }
182
+ self
183
+ end
184
+
185
+ protected
186
+
187
+ def wrap_value(value, mode: nil) = nil.equal?(value) ? NIL_VALUE : @manager.wrap(value, mode:)
188
+ def unwrap_value(value) = NIL_VALUE.equal?(value) ? nil : @manager.unwrap(value)
189
+
190
+ private
191
+
192
+ def marshal_map_value(value) = super(NIL_VALUE.equal?(value) ? nil : value)
193
+
194
+ def marshal_restore_map_value(data)
195
+ value = super
196
+ nil.equal?(value) ? NIL_VALUE : value
197
+ end
198
+
199
+ def each_for_inspect(&) = @map.each(&)
200
+
201
+ def inspect_pair(inspector, key, value)
202
+ inspector.hash_pair(key, value, @manager) { inspect_value(inspector, value) }
203
+ end
204
+
205
+ def inspect_value(inspector, value)
206
+ value = nil if NIL_VALUE.equal?(value)
207
+ super(inspector, value, @manager)
208
+ end
209
+
210
+ def new_mode_manager(mode:) = marshal_mode_manager(mode)
211
+
212
+ def check_key(key)
213
+ return if Ractor.shareable?(key)
214
+ raise Ractor::IsolationError, "key must be Ractor-shareable"
215
+ end
216
+
217
+ def wrap_comparison(value) = wrap_value(value, mode: compare_values_by_identity? ? :local : :copy)
218
+
219
+ def unwrap_result(result)
220
+ return unwrap_value(result) unless TIMED_OUT.equal?(result)
221
+ yield if block_given?
222
+ end
223
+
224
+ def values_equal?(left, right) = @manager.same_value?(left, right, identity: compare_values_by_identity?)
225
+ end
226
+ end
227
+ end