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,381 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Abstract
7
+ # @abstract Super class for {Map maps} with added concurrency features.
8
+ class ConcurrentMap < Map
9
+ include DuplicableMap
10
+
11
+ # @api private
12
+ def transaction_wrapper(transaction) = Transaction::Map.new(transaction, self, internal_map)
13
+
14
+ # (see Map#[])
15
+ def [](key) = internal_map[key]
16
+
17
+ # (see Map#[]=)
18
+ def []=(key, value)
19
+ internal_map[key] = value
20
+ end
21
+
22
+ # (see Map#fetch)
23
+ def fetch(*arguments)
24
+ unless arguments.length.between?(1, 2)
25
+ raise ArgumentError, "wrong number of arguments (given #{arguments.length}, expected 1..2)"
26
+ end
27
+
28
+ key, default = arguments
29
+ warn "block supersedes default value argument", uplevel: 1 if block_given? && arguments.length == 2
30
+ internal_map.fetch(key) do
31
+ return yield(key) if block_given?
32
+ return default if arguments.length == 2
33
+ raise KeyError.new("key not found: #{key.inspect}", receiver: self, key: key)
34
+ end
35
+ end
36
+
37
+ # Read the value associated with a key, waiting for atomic-update access if necessary.
38
+ # @param key [BasicObject] The key to look up.
39
+ # @param timeout [Numeric, nil] The maximum number of seconds to wait for access.
40
+ # @yield Called if access cannot be acquired before the timeout.
41
+ # @yieldreturn [BasicObject] The fallback value to return.
42
+ # @return [BasicObject, nil]
43
+ # The associated value, nil if the key is absent, or the fallback result if the operation times out.
44
+ def get(key, timeout: nil, &) = internal_map.get(key, timeout:, &)
45
+
46
+ # Associate a value with a key, waiting for atomic-update access if necessary.
47
+ # @param key [BasicObject] The key to store.
48
+ # @param value [BasicObject] The value to store.
49
+ # @param timeout [Numeric, nil] The maximum number of seconds to wait for access.
50
+ # @yield Called if access cannot be acquired before the timeout.
51
+ # @yieldreturn [BasicObject] The fallback value to return.
52
+ # @return [BasicObject, nil] `value` on success, or the fallback result or nil on timeout.
53
+ def store(key, value, timeout: nil, &) = internal_map.store(key, value, timeout:, &)
54
+
55
+ # Replace the value associated with a key and return its previous value.
56
+ # @param key [BasicObject] The key to update.
57
+ # @param replacement [BasicObject] The value to store.
58
+ # @param timeout [Numeric, nil] The maximum number of seconds to wait for access.
59
+ # @yield Called if access cannot be acquired before the timeout.
60
+ # @yieldreturn [BasicObject] The fallback value to return.
61
+ # @return [BasicObject, nil]
62
+ # The previous value, nil if the key was absent, or the fallback result if the operation times out.
63
+ def swap(key, replacement, timeout: nil, &) = internal_map.swap(key, replacement, timeout:, &)
64
+
65
+ # Atomically fetch an existing value or compute and store a value for an absent key.
66
+ # @param key [BasicObject] The key to look up or store.
67
+ # @param timeout [Numeric, nil] The maximum number of seconds to wait for access.
68
+ # @yield Called without arguments when the key is absent.
69
+ # @yieldreturn [BasicObject] The value to store and return.
70
+ # @return [BasicObject, nil] The existing or newly stored value, or nil on timeout.
71
+ # @raise [LocalJumpError] If no block is given.
72
+ def store_if_absent(key, timeout: nil, &) = internal_map.store_if_absent(key, timeout:, &)
73
+
74
+ # Atomically replace a value if the key is present and its current value matches `expected`.
75
+ # The configured value-comparison mode determines whether matching uses equality or identity.
76
+ # @param key [BasicObject] The key to update.
77
+ # @param expected [BasicObject] The value expected to be currently associated with the key.
78
+ # @param replacement [BasicObject] The value to store when the current value matches.
79
+ # @param timeout [Numeric, nil] The maximum number of seconds to wait for access.
80
+ # @return [Boolean] Whether the value was replaced. Returns false on timeout.
81
+ def compare_and_set(key, expected, replacement, timeout: nil)
82
+ internal_map.compare_and_set(key, expected, replacement, timeout:)
83
+ end
84
+
85
+ # Atomically replace the value associated with a key with the block result.
86
+ # The block receives nil when the key is absent or its current value is nil.
87
+ # @param key [BasicObject] The key to update.
88
+ # @param timeout [Numeric, nil] The maximum number of seconds to wait for access.
89
+ # @yield [value] Called after access is acquired.
90
+ # @yieldparam value [BasicObject, nil] The current value, or nil if the key is absent.
91
+ # @yieldreturn [BasicObject] The value to store and return.
92
+ # @return [BasicObject, nil] The newly stored value, or nil on timeout.
93
+ # @raise [LocalJumpError] If no block is given.
94
+ def update(key, timeout: nil, &) = internal_map.update(key, timeout:, &)
95
+
96
+ # Atomically insert `initial` for an absent key or replace an existing value with the block result.
97
+ # The block is not called when the key is absent.
98
+ # @param key [BasicObject] The key to insert or update.
99
+ # @param initial [BasicObject] The value to store when the key is absent.
100
+ # @param timeout [Numeric, nil] The maximum number of seconds to wait for access.
101
+ # @yield [value] Called when the key is present.
102
+ # @yieldparam value [BasicObject] The current value.
103
+ # @yieldreturn [BasicObject] The replacement value to store and return.
104
+ # @return [BasicObject, nil] The initial or replacement value, or nil on timeout.
105
+ # @raise [LocalJumpError] If no block is given.
106
+ def upsert(key, initial, timeout: nil, &) = internal_map.upsert(key, initial, timeout:, &)
107
+
108
+ # Wait until a block condition matches the current value.
109
+ # One timeout budget covers all checks and waits. The block is not interrupted.
110
+ # @yieldparam value [BasicObject, nil] the current value
111
+ # @yieldreturn [Boolean] whether the value matches
112
+ # An absent key is observed as nil.
113
+ # @param key [BasicObject] the key to observe
114
+ # @param timeout [Numeric, nil] the total seconds available
115
+ # @return [BasicObject, nil] the matching value, or nil on timeout
116
+ # @raise [LocalJumpError] if no block is given
117
+ def wait_until(key, timeout: nil, &) = Internal.wait_until(self, key, timeout:, &)
118
+
119
+ # Wait while the block returns a truthy value.
120
+ # @yieldparam value [BasicObject, nil] the current value
121
+ # @yieldreturn [BasicObject] a truthy value to keep waiting, or nil or false to stop
122
+ # @param key [BasicObject] the key to observe
123
+ # @param timeout [Numeric, nil] the total seconds available
124
+ # @return [BasicObject, nil] the value when the condition becomes false, or nil on timeout
125
+ # @raise [LocalJumpError] if no block is given
126
+ def wait_while(key, timeout: nil)
127
+ raise LocalJumpError, "no block given" unless block_given?
128
+ wait_until(key, timeout:) { |value| !yield(value) }
129
+ end
130
+
131
+ # Wait while `object === value` is true.
132
+ # @param key [BasicObject] the key to observe
133
+ # @param object [#===] the pattern to stop matching
134
+ # @param timeout [Numeric, nil] the total seconds available
135
+ # @return [BasicObject, nil] the first nonmatching value, or nil on timeout
136
+ def wait_while_match(key, object, timeout: nil)
137
+ wait_while(key, timeout:) { |value| object === value } # rubocop:disable Style/CaseEquality
138
+ end
139
+
140
+ # (see #wait_until_changed)
141
+ def wait_while_value(...) = wait_until_changed(...)
142
+
143
+ # Wait until the current value equals an object using the configured comparison mode.
144
+ # @param key [BasicObject] the key to observe
145
+ # @param object [BasicObject, nil] the value to compare with the current value
146
+ # @param timeout [Numeric, nil] the total seconds available
147
+ # @return [BasicObject, nil] the matching value, or nil on timeout
148
+ def wait_until_value(key, object, timeout: nil)
149
+ wait_until(key, timeout:) { |value| compare_values_by_identity? ? object.equal?(value) : object == value }
150
+ end
151
+
152
+ # Wait until `object === value` is true.
153
+ # @param object [#===] the pattern to match
154
+ # @param timeout [Numeric, nil] the total seconds available
155
+ # @return [BasicObject, nil] the matching value, or nil on timeout
156
+ def wait_until_match(key, object, timeout: nil)
157
+ wait_until(key, timeout:) { |value| object === value } # rubocop:disable Style/CaseEquality
158
+ end
159
+
160
+ # Wait until the value associated with a key no longer matches `expected`.
161
+ # An absent key is observed as nil. The configured value-comparison mode determines how values are matched.
162
+ # @param key [BasicObject] The key to observe.
163
+ # @param expected [BasicObject] The value to wait to change from.
164
+ # @param timeout [Numeric, nil] The maximum number of seconds to wait.
165
+ # @yield Called if the value has not changed before the timeout.
166
+ # @yieldreturn [BasicObject] The fallback value to return.
167
+ # @return [BasicObject, nil] The changed value, or the fallback result or nil on timeout.
168
+ def wait_until_changed(key, expected, timeout: nil, &)
169
+ internal_map.wait_until_changed(key, expected, timeout:, &)
170
+ end
171
+
172
+ # Wait until a key is associated with a non-nil value.
173
+ # @param key [BasicObject] The key to observe.
174
+ # @param timeout [Numeric, nil] The maximum number of seconds to wait.
175
+ # @yield Called if the value is still nil when the timeout elapses.
176
+ # @yieldreturn [BasicObject] The fallback value to return.
177
+ # @return [BasicObject, nil] The non-nil value, or the fallback result or nil on timeout.
178
+ def wait_until_non_nil(key, timeout: nil, &) = internal_map.wait_until_non_nil(key, timeout:, &)
179
+
180
+ # (see Map#key?)
181
+ def key?(key) = internal_map.key?(key)
182
+
183
+ # (see Map#getkey)
184
+ def getkey(key) = internal_map.getkey(key)
185
+
186
+ # (see Map#size)
187
+ def size = internal_map.size
188
+
189
+ # (see Map#compare_keys_by_identity?)
190
+ def compare_keys_by_identity? = internal_map.compare_keys_by_identity?
191
+
192
+ # (see Map#compare_values_by_identity?)
193
+ def compare_values_by_identity? = internal_map.compare_values_by_identity?
194
+
195
+ # (see Map#keys)
196
+ def keys = internal_map.keys
197
+
198
+ # Return the values currently stored in the map.
199
+ # @return [Array<BasicObject>] A new array of values in iteration order.
200
+ def values = each_value.to_a
201
+
202
+ # Iterate over entries captured when iteration begins.
203
+ # The map can be modified safely from the block.
204
+ # (see Map#each)
205
+ def each(&block)
206
+ return enum_for(__callee__) { size } unless block
207
+
208
+ internal_map.each(&block)
209
+ self
210
+ end
211
+
212
+ # Iterate incrementally without copying every entry first.
213
+ # Entries can be removed or updated by the block. Insertion or clearing
214
+ # may invalidate traversal and raise RuntimeError. No entry lock is held
215
+ # while the block runs. A small batch of entries may be retained at once.
216
+ # @return [self, Enumerator]
217
+ # @api private
218
+ def each_live
219
+ return enum_for(__method__) { size } unless block_given?
220
+ internal_map.each_live { yield it }
221
+ self
222
+ end
223
+
224
+ # (see Map#each_pair)
225
+ alias each_pair each
226
+
227
+ # (see Map#each_key)
228
+ def each_key(&block)
229
+ return enum_for(__callee__) { size } unless block
230
+
231
+ internal_map.each_key(&block)
232
+ self
233
+ end
234
+
235
+ # (see Map#each_value)
236
+ def each_value(&block)
237
+ return enum_for(__callee__) { size } unless block
238
+
239
+ internal_map.each_value(&block)
240
+ self
241
+ end
242
+
243
+ # (see Map#delete)
244
+ def delete(key) = internal_map.delete(key)
245
+
246
+ # (see Map#clear)
247
+ def clear
248
+ internal_map.clear
249
+ self
250
+ end
251
+
252
+ # Delete entries selected by the block and return self.
253
+ #
254
+ # Keys are captured before iteration. Each block and its decision use the existing atomic-update coordination.
255
+ # Blocks see the current value, and keys deleted before their turn are skipped.
256
+ # The whole operation is not atomic. Exceptions leave earlier changes in place.
257
+ # The same reentrancy restrictions as {#update} apply inside each block.
258
+ #
259
+ # @yieldparam key [BasicObject] the stored key
260
+ # @yieldparam value [BasicObject] the current value
261
+ # @return [self, Enumerator]
262
+ def delete_if(&)
263
+ return enum_for(__method__) { size } unless block_given?
264
+ check_frozen! if respond_to?(:check_frozen!, true)
265
+ filter_entries(&)
266
+ self
267
+ end
268
+
269
+ # Like {#delete_if}, but return nil when this operation deletes no entries.
270
+ # @return [self, nil, Enumerator]
271
+ def reject!(&)
272
+ return enum_for(__method__) { size } unless block_given?
273
+ check_frozen! if respond_to?(:check_frozen!, true)
274
+ self if filter_entries(&)
275
+ end
276
+
277
+ # Remove nil values using per-key update coordination. False values are retained.
278
+ # The whole operation is not atomic, as with {#delete_if}.
279
+ # @return [self, nil] self if this operation deletes entries, otherwise nil.
280
+ def compact! = reject! { |_, value| nil.equal?(value) }
281
+
282
+ # Keep entries selected by the block. Uses the same coordination as {#delete_if}.
283
+ # @return [self, Enumerator]
284
+ def keep_if
285
+ return enum_for(__method__) { size } unless block_given?
286
+ check_frozen! if respond_to?(:check_frozen!, true)
287
+ filter_entries { |key, value| !yield(key, value) }
288
+ self
289
+ end
290
+
291
+ # Like {#keep_if}, but return nil when this operation deletes no entries.
292
+ # @return [self, nil, Enumerator]
293
+ def select!
294
+ return enum_for(__method__) { size } unless block_given?
295
+ check_frozen! if respond_to?(:check_frozen!, true)
296
+ self if filter_entries { |key, value| !yield(key, value) }
297
+ end
298
+ alias filter! select!
299
+
300
+ # Replace each existing value with the block result using atomic-update coordination.
301
+ #
302
+ # Keys are captured before iteration. Missing keys are skipped and earlier changes survive exceptions.
303
+ # Results use this map's transfer mode. The same reentrancy restrictions as {#update} apply.
304
+ #
305
+ # @yieldparam value [BasicObject] the current value
306
+ # @return [self, Enumerator]
307
+ def transform_values!
308
+ return enum_for(__method__) { size } unless block_given?
309
+ check_frozen! if respond_to?(:check_frozen!, true)
310
+ keys.each do |key|
311
+ modify_entry(key, canonical: true) do |present, value|
312
+ present ? yield(value) : Internal::MAP_KEEP
313
+ end
314
+ end
315
+ self
316
+ end
317
+
318
+ # Apply input maps in order. A block resolves each collision under atomic-update coordination.
319
+ #
320
+ # Incoming keys use normal lookup rules. Values use this map's transfer mode, including move semantics.
321
+ # The operation is not atomic across keys. Exceptions leave earlier changes in place.
322
+ #
323
+ # @param others [Array<Map, Hash, #to_hash>] mappings to apply in order
324
+ # @yieldparam key [BasicObject] the incoming key
325
+ # @yieldparam old_value [BasicObject] the current value
326
+ # @yieldparam new_value [BasicObject] the incoming value
327
+ # @return [self]
328
+ def merge!(*others)
329
+ check_frozen! if respond_to?(:check_frozen!, true)
330
+ others.each do |other|
331
+ unless Map === other
332
+ other = Hash.try_convert(other) || raise(TypeError, "input must be a Map, Hash, or respond to #to_hash")
333
+ end
334
+ other.each_pair do |key, value|
335
+ if block_given?
336
+ modify_entry(key) { |present, old| present ? yield(key, old, value) : value }
337
+ else
338
+ self[key] = value
339
+ end
340
+ end
341
+ end
342
+ self
343
+ end
344
+
345
+ private
346
+
347
+ def modify_entry(key, canonical: false)
348
+ map = internal_map
349
+ map = map.instance_variable_get(:@map) if canonical && map.is_a?(Internal::KeyNormalizer::ConcurrentMap)
350
+ map.modify(key) do |present, value|
351
+ replacement = yield(present, present ? unwrap_value(value) : nil)
352
+ next replacement if Internal::MAP_KEEP.equal?(replacement) || Internal::MAP_DELETE.equal?(replacement)
353
+ wrap_value(replacement)
354
+ end
355
+ end
356
+
357
+ def filter_entries
358
+ changed = false
359
+ keys.each do |key|
360
+ deleted = modify_entry(key, canonical: true) do |present, value|
361
+ present && yield(key, value) ? Internal::MAP_DELETE : Internal::MAP_KEEP
362
+ end
363
+ changed = true if deleted
364
+ end
365
+ changed
366
+ end
367
+
368
+ def copy_map_backend(source, empty: false)
369
+ raise TypeError, "copy this backend through its public map" unless source
370
+ source = source.instance_variable_get(:@map) if source.is_a?(Internal::KeyNormalizer::ConcurrentMap)
371
+ copied = source.class.new(
372
+ compare_keys_by_identity: source.compare_keys_by_identity?,
373
+ compare_values_by_identity: source.compare_values_by_identity?,
374
+ )
375
+ source.each { |key, value| copied[key] = value } unless empty
376
+ normalizer = instance_variable_get(:@key_normalizer)
377
+ Internal::KeyNormalizer.wrap_concurrent(copied, normalizer)
378
+ end
379
+ end
380
+ end
381
+ end
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Abstract
7
+ # @abstract Common numeric interface and atomic operations for counters.
8
+ # @note This is a module rather than a class so {Farce::Counter} can inherit
9
+ # directly from the native counter and avoid delegation overhead.
10
+ module Counter
11
+ include Internal::MarshalSupport::Counter
12
+ include Internal::Copyable
13
+ include Internal::Inspect
14
+
15
+ def self.included(base)
16
+ Internal.prepare_mutable_numeric(base)
17
+ super
18
+ end
19
+
20
+ # Numeric's default copying returns self, which is unsuitable for mutable counters.
21
+ define_method(:dup, Kernel.instance_method(:dup))
22
+ define_method(:clone, Kernel.instance_method(:clone))
23
+
24
+ include Value
25
+ include Internal::ValueSerialization
26
+
27
+ # Wait until the current value differs from the expected value.
28
+ # @param expected [Integer] the value to wait to change from
29
+ # @param timeout [Numeric, nil] the total seconds available
30
+ # @yield called when the timeout expires
31
+ # @return [Integer, BasicObject, nil] the changed value or timeout fallback
32
+ def wait_until_changed(expected, timeout: nil)
33
+ signal = change_signal
34
+ Internal.with_timeout(timeout) do |_, deadline|
35
+ observed = signal.generation
36
+ current = value
37
+ return current unless expected == current
38
+ break unless signal.wait(observed, timeout: Internal.remaining_timeout(deadline))
39
+ end
40
+ yield if block_given?
41
+ end
42
+
43
+ # Wait until a block condition matches the current value.
44
+ # One timeout budget covers all checks and waits. The block is not interrupted.
45
+ # @yieldparam value [Integer] the current value
46
+ # @yieldreturn [Boolean] whether the value matches
47
+ # @param timeout [Numeric, nil] the total seconds available
48
+ # @return [Integer, nil] the matching value, or nil on timeout
49
+ # @raise [LocalJumpError] if no block is given
50
+ def wait_until(timeout: nil, &) = Internal.wait_until(self, timeout:, &)
51
+
52
+ # Wait while the block returns a truthy value.
53
+ # @yieldparam value [Integer] the current value
54
+ # @yieldreturn [BasicObject] a truthy value to keep waiting, or nil or false to stop
55
+ # @param timeout [Numeric, nil] the total seconds available
56
+ # @return [Integer, nil] the value when the condition becomes false, or nil on timeout
57
+ # @raise [LocalJumpError] if no block is given
58
+ def wait_while(timeout: nil)
59
+ raise LocalJumpError, "no block given" unless block_given?
60
+ wait_until(timeout:) { |value| !yield(value) }
61
+ end
62
+
63
+ # Wait while `object === value` is true.
64
+ # @param object [#===] the pattern to stop matching
65
+ # @param timeout [Numeric, nil] the total seconds available
66
+ # @return [Integer, nil] the first nonmatching value, or nil on timeout
67
+ def wait_while_match(object, timeout: nil)
68
+ wait_while(timeout:) { |value| object === value } # rubocop:disable Style/CaseEquality
69
+ end
70
+
71
+ # (see #wait_until_changed)
72
+ def wait_while_value(...) = wait_until_changed(...)
73
+
74
+ # Wait until `object == value` is true.
75
+ # Counters compare integer values by equality.
76
+ # @param object [BasicObject] the value to compare with the current value
77
+ # @param timeout [Numeric, nil] the total seconds available
78
+ # @return [Integer, nil] the matching value, or nil on timeout
79
+ def wait_until_value(object, timeout: nil)
80
+ wait_until(timeout:) { |value| object == value }
81
+ end
82
+
83
+ # Wait until `object === value` is true.
84
+ # @param object [#===] the pattern to match
85
+ # @param timeout [Numeric, nil] the total seconds available
86
+ # @return [Integer, nil] the matching value, or nil on timeout
87
+ def wait_until_match(object, timeout: nil)
88
+ wait_until(timeout:) { |value| object === value } # rubocop:disable Style/CaseEquality
89
+ end
90
+
91
+ # Wait until the value is strictly below the limit.
92
+ # @param limit [Numeric, String, #to_int] the upper bound, converted to an Integer
93
+ # @param timeout [Numeric, nil] the total seconds available
94
+ # @return [Integer, nil] the matching value, or nil on timeout
95
+ def wait_until_below(limit, timeout: nil)
96
+ limit = Integer(limit)
97
+ wait_until(timeout:) { |value| value < limit }
98
+ end
99
+
100
+ # Wait until the value is strictly above the floor.
101
+ # @param floor [Numeric, String, #to_int] the lower bound, converted to an Integer
102
+ # @param timeout [Numeric, nil] the total seconds available
103
+ # @return [Integer, nil] the matching value, or nil on timeout
104
+ def wait_until_above(floor, timeout: nil)
105
+ floor = Integer(floor)
106
+ wait_until(timeout:) { |value| value > floor }
107
+ end
108
+
109
+ # Wait while the value is strictly above the limit.
110
+ # @param limit [Numeric, String, #to_int] the upper bound, converted to an Integer
111
+ # @param timeout [Numeric, nil] the total seconds available
112
+ # @return [Integer, nil] the first value at or below the limit, or nil on timeout
113
+ def wait_while_above(limit, timeout: nil)
114
+ limit = Integer(limit)
115
+ wait_until(timeout:) { |value| value <= limit }
116
+ end
117
+
118
+ # Wait while the value is strictly below the floor.
119
+ # @param floor [Numeric, String, #to_int] the lower bound, converted to an Integer
120
+ # @param timeout [Numeric, nil] the total seconds available
121
+ # @return [Integer, nil] the first value at or above the floor, or nil on timeout
122
+ def wait_while_below(floor, timeout: nil)
123
+ floor = Integer(floor)
124
+ wait_until(timeout:) { |value| value >= floor }
125
+ end
126
+
127
+ # Reset the counter to its initial value.
128
+ # @return [self] Returns self for chaining.
129
+ def reset
130
+ self.value = initial
131
+ self
132
+ end
133
+
134
+ # Increment the counter by one if its current value is below the limit.
135
+ # The check and increment happen atomically.
136
+ # @param [Numeric, String, #to_int] limit The upper bound, converted to an Integer.
137
+ # @return [Boolean] true if the counter changed, otherwise false.
138
+ def increment_if_below(limit) # rubocop:disable Naming/PredicateMethod
139
+ limit = Integer(limit)
140
+ current = value
141
+
142
+ Internal::Freeze.check(self)
143
+
144
+ while current < limit
145
+ return true if compare_and_set(current, current + 1)
146
+ current = value
147
+ end
148
+
149
+ false
150
+ end
151
+
152
+ # Decrement the counter by one if its current value is above the floor.
153
+ # The check and decrement happen atomically.
154
+ # @param [Numeric, String, #to_int] floor The lower bound, converted to an Integer.
155
+ # @return [Boolean] true if the counter changed, otherwise false.
156
+ def decrement_if_above(floor) # rubocop:disable Naming/PredicateMethod
157
+ floor = Integer(floor)
158
+ current = value
159
+
160
+ Internal::Freeze.check(self)
161
+
162
+ while current > floor
163
+ return true if compare_and_set(current, current - 1)
164
+ current = value
165
+ end
166
+
167
+ false
168
+ end
169
+
170
+ # @overload add(by = 1)
171
+ # (see #increment)
172
+ def add(...) = increment(...)
173
+
174
+ methods = Integer.public_instance_methods - Object.public_instance_methods - [:singleton_method_added]
175
+ methods += %i[+ - / * ** <=> coerce rationalize to_i to_int to_f to_c to_r to_s]
176
+ methods.uniq!
177
+ Internal.delegate(self, :value, *methods)
178
+
179
+ # @api private
180
+ def inspect_with(inspector)
181
+ super do
182
+ inspector.breakable
183
+ inspector.object(value)
184
+ end
185
+ end
186
+
187
+ private
188
+
189
+ def method_missing(...) = value.public_send(...)
190
+ def respond_to_missing?(method, ...) = value.respond_to?(method)
191
+ end
192
+ end
193
+ end