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,172 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Abstract
7
+ # @abstract A set maintained in ascending comparator order.
8
+ # Membership, insertion, and deletion use `<=>`. Two elements occupy the
9
+ # same slot when their comparison returns zero. Elements must be mutually
10
+ # comparable and must not change their ordering while stored. Incompatible
11
+ # elements raise during insertion or lookup.
12
+ class SortedSet < Set
13
+ # Construct a set in ascending comparator order.
14
+ # @overload initialize(enumerable = nil, normalize: nil, compare_by_identity: false, mode: :copy, **options)
15
+ # @param enumerable [#each, nil] The initial elements, or nil for an empty set.
16
+ # @param normalize [Symbol, Proc, Hash, Farce::Abstract::Map, nil] The element normalizer.
17
+ # @param compare_by_identity [Boolean] Must be false. Membership uses <=>.
18
+ # @param mode [Symbol] The default transfer mode. Only Farce::SortedSet accepts
19
+ # this option, which defaults to :copy.
20
+ # @param options [Hash] Additional options for the selected variant.
21
+ # @option options [Symbol] scope (:ractor) The scope used by Farce::Local::SortedSet.
22
+ # @yield [element] Optionally transform each initial element before normalization.
23
+ # @yieldparam element [BasicObject] An element from enumerable.
24
+ # @yieldreturn [BasicObject] The comparable element to normalize and store.
25
+ # @return [Farce::Abstract::SortedSet] The new sorted set.
26
+ # @raise [ArgumentError] If compare_by_identity is true.
27
+ # @see Farce::Abstract::Set#initialize Additional options for Local variants.
28
+ def initialize(
29
+ enumerable = nil, normalize: nil, compare_by_identity: false, mode: UNDEFINED, **, &transform
30
+ )
31
+ raise ArgumentError, "sorted sets do not support identity comparison" if compare_by_identity
32
+ super(enumerable, normalize:, compare_by_identity: false, mode:, **, &transform)
33
+ end
34
+
35
+ # @api private
36
+ def transaction_wrapper(transaction) = Transaction::SortedSet.new(transaction, self, @map)
37
+
38
+ # Return whether this set has comparator-equivalent members in the same order.
39
+ # @param other [BasicObject] The object to compare against.
40
+ # @return [Boolean] Whether other is a Farce sorted set with comparator-equivalent members.
41
+ def ==(other)
42
+ return true if equal?(other)
43
+ return false unless other.is_a?(Abstract::SortedSet) && size == other.size
44
+ ordered_keys.zip(other.ordered_keys).all? { comparator_equal?(_1, _2) }
45
+ end
46
+
47
+ # Compare canonical ordered members using eql?.
48
+ # @param other [BasicObject] The object to compare against.
49
+ # @return [Boolean] Whether other is a Farce sorted set with eql? ordered members.
50
+ def eql?(other)
51
+ return true if equal?(other)
52
+ other.is_a?(Abstract::SortedSet) && ordered_keys.eql?(other.ordered_keys)
53
+ end
54
+
55
+ # Return a hash derived from the canonical ordered members.
56
+ # @return [Integer] The hash code.
57
+ def hash = ordered_keys.hash
58
+
59
+ # Remove every comparator-equivalent member yielded by enumerable.
60
+ # @param enumerable [#each] The elements to normalize and remove by comparison.
61
+ # @return [self] The set.
62
+ def subtract(enumerable)
63
+ check_frozen!
64
+ if ordered_compatible?(enumerable)
65
+ enumerable.each_stored { |key, _| @map.delete(key) }
66
+ else
67
+ each_input(enumerable) do |element|
68
+ key = lookup_key(normalize_element(element))
69
+ @map.delete(key) unless MISSING_KEY.equal?(key)
70
+ end
71
+ end
72
+ self
73
+ end
74
+
75
+ # Return a same-kind set containing members present by comparator in every input.
76
+ # @param enumerables [Array<#each>] The collections whose comparator-equivalent members must be present.
77
+ # @return [Farce::Abstract::SortedSet] A new sorted set of the same class with the same settings.
78
+ def intersection(*enumerables)
79
+ indexes = enumerables.map { ordered_index(it) }
80
+ dup.filter_stored! { |key, _| indexes.all? { it.key?(key) } }
81
+ end
82
+ alias & intersection
83
+
84
+ # Return whether every member has a comparator-equivalent member in other.
85
+ # @param other [Farce::Abstract::Set, ::Set] The set to compare against.
86
+ # @return [Boolean] Whether the comparator-based relation holds.
87
+ # @raise [ArgumentError] If other is not a Farce or Ruby set.
88
+ def subset?(other)
89
+ validate_set_like(other)
90
+ index = ordered_index(other)
91
+ size <= index.size && ordered_keys.all? { index.key?(it) }
92
+ end
93
+ alias <= subset?
94
+
95
+ # Return whether this is a proper comparator subset of other.
96
+ # @param other [Farce::Abstract::Set, ::Set] The set to compare against.
97
+ # @return [Boolean] Whether the comparator-based relation holds.
98
+ # @raise [ArgumentError] If other is not a Farce or Ruby set.
99
+ def proper_subset?(other)
100
+ validate_set_like(other)
101
+ index = ordered_index(other)
102
+ size < index.size && ordered_keys.all? { index.key?(it) }
103
+ end
104
+ alias < proper_subset?
105
+
106
+ # Return whether every member of other has a comparator-equivalent member here.
107
+ # @param other [Farce::Abstract::Set, ::Set] The set to compare against.
108
+ # @return [Boolean] Whether the comparator-based relation holds.
109
+ # @raise [ArgumentError] If other is not a Farce or Ruby set.
110
+ def superset?(other)
111
+ validate_set_like(other)
112
+ index = ordered_index(other)
113
+ size >= index.size && index.keys.all? { @map.key?(it) }
114
+ end
115
+ alias >= superset?
116
+
117
+ # Return whether this is a proper comparator superset of other.
118
+ # @param other [Farce::Abstract::Set, ::Set] The set to compare against.
119
+ # @return [Boolean] Whether the comparator-based relation holds.
120
+ # @raise [ArgumentError] If other is not a Farce or Ruby set.
121
+ def proper_superset?(other)
122
+ validate_set_like(other)
123
+ index = ordered_index(other)
124
+ size > index.size && index.keys.all? { @map.key?(it) }
125
+ end
126
+ alias > proper_superset?
127
+
128
+ # Return whether another set has a comparator-equivalent member.
129
+ # @param other [Farce::Abstract::Set, ::Set] The set to compare against.
130
+ # @return [Boolean] Whether the comparator-based relation holds.
131
+ # @raise [ArgumentError] If other is not a Farce or Ruby set.
132
+ def intersect?(other)
133
+ validate_set_like(other)
134
+ index = ordered_index(other)
135
+ left, right = size <= index.size ? [ordered_keys, index] : [index.keys, @map]
136
+ left.any? { right.key?(it) }
137
+ end
138
+
139
+ protected
140
+
141
+ def ordered_keys = @map.keys
142
+ def ordered? = true
143
+
144
+ private
145
+
146
+ def ordered_compatible?(other)
147
+ canonical_compatible?(other) && other.is_a?(Abstract::SortedSet)
148
+ end
149
+
150
+ def ordered_index(enumerable)
151
+ index = new_map(nil, compare_keys_by_identity: false, **copy_map_options(self))
152
+ if ordered_compatible?(enumerable)
153
+ enumerable.each_stored { |key, _| index[key] = true }
154
+ else
155
+ each_input(enumerable) do |element|
156
+ key = lookup_key(normalize_element(element))
157
+ index[key] = true unless MISSING_KEY.equal?(key)
158
+ end
159
+ end
160
+ index
161
+ end
162
+
163
+ def comparator_equal?(left, right)
164
+ comparison = left <=> right
165
+ return comparison.zero? if comparison
166
+ raise ArgumentError, "comparison of #{left.class} with #{right.class} failed"
167
+ end
168
+
169
+ def identity_membership?(_element) = false
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Abstract
7
+ # @abstract Shared timer scheduling and blocking behavior.
8
+ class TimerQueue < Queue
9
+ include Internal::BlockingPriorityQueue
10
+
11
+ # @param capacity [Integer, nil] the maximum number of values, or nil for an unbounded queue
12
+ def initialize(capacity: nil, track_age: false)
13
+ super
14
+ end
15
+
16
+ # Add a value to become available at the given time.
17
+ # @param value [BasicObject] the value to add
18
+ # @param non_block [Boolean] whether to raise an exception when the queue is at capacity
19
+ # @param timeout [Numeric, nil] maximum number of seconds to wait for capacity
20
+ # @param time_options [Hash{Symbol => Object}] a scheduling option accepted by {Clock.parse}:
21
+ # `at:`, `time:`, `timeout_at:`, `delay:`, `in:`, `offset:`, `wait:`, or `clock:`.
22
+ # With no scheduling option, the value is available immediately. Since `timeout:` controls the capacity wait,
23
+ # use `delay:` or `wait:` to schedule a relative offset.
24
+ # @raise [ThreadError] when the queue is at capacity and non_block is true
25
+ # @return [Boolean] whether the value was added
26
+ def push(value, non_block = false, timeout: nil, **time_options) # rubocop:disable Style/OptionalBooleanParameter
27
+ at = Clock.parse(time_options)
28
+ push_to_storage(at, non_block, value, timeout:)
29
+ end
30
+
31
+ # Remove the earliest value, waiting until its timestamp is reached.
32
+ # @param timeout [Numeric, nil] maximum number of seconds to wait
33
+ # @yield called when the timeout expires first
34
+ # @return [BasicObject, nil] the value or the fallback result
35
+ def pop(non_block = false, timeout: nil) # rubocop:disable Style/OptionalBooleanParameter
36
+ return try_pop { raise ThreadError, "queue empty" } if non_block
37
+ deadline = timeout_at(timeout) unless timeout.nil?
38
+
39
+ while true
40
+ empty = false
41
+ value = internal_queue.pop_before(Clock.now) { empty = true }
42
+ return value unless empty
43
+ return block_given? ? yield : nil if UNDEFINED.equal?(wait_for_timestamp(deadline))
44
+ end
45
+ end
46
+
47
+ # Try to add a value without waiting for capacity.
48
+ # @param value [BasicObject] the value to add
49
+ # @param time_options [Hash{Symbol => Object}] a scheduling option accepted by {Clock.parse}:
50
+ # `at:`, `time:`, `timeout_at:`, `delay:`, `in:`, `offset:`, `timeout:`, `wait:`, or `clock:`.
51
+ # With no scheduling option, the value is available immediately.
52
+ # @yield called when the queue is at capacity
53
+ # @return [Boolean, BasicObject] true, or the fallback result when full
54
+ def try_push(value, **time_options)
55
+ at = Clock.parse(time_options)
56
+ return true if internal_queue.push(at, value)
57
+ block_given? ? yield : false
58
+ end
59
+
60
+ # Try to remove the earliest value only if its timestamp has been reached.
61
+ # @yield called when no value is ready
62
+ # @return [BasicObject, nil] the value or the fallback result
63
+ def try_pop(&) = internal_queue.pop_before(Clock.now, &)
64
+
65
+ # Return the earliest value without removing it, whether or not it is due.
66
+ # @yield called when the queue is empty
67
+ # @return [BasicObject, nil] the value or the fallback result
68
+ def peek(&) = internal_queue.peek(&)
69
+
70
+ # Return the earliest timestamp without removing it.
71
+ # @yield called when the queue is empty
72
+ # @return [Float, nil] the timestamp or the fallback result
73
+ def first_timestamp(&) = internal_queue.peek_priority(&)
74
+
75
+ # Return the latest timestamp without removing it.
76
+ # @yield called when the queue is empty
77
+ # @return [Float, nil] the timestamp or the fallback result
78
+ def last_timestamp(&) = internal_queue.peek_last_priority(&)
79
+
80
+ # Checks whether the earliest timestamp has been reached.
81
+ # @param leeway [Numeric] how much leeway to allow for clock drift and scheduling delays
82
+ def overdue?(leeway: 0)
83
+ return false unless timestamp = first_timestamp
84
+ timestamp <= Clock.in(leeway)
85
+ end
86
+
87
+ # Returns how long the earliest timestamp has been overdue, or nil if it is not yet due.
88
+ # @param leeway [Numeric] how much leeway to allow for clock drift and scheduling delays
89
+ # @return [Float, nil] the number of seconds overdue, or nil if the earliest timestamp is not yet due
90
+ def overdue_by(leeway: 0)
91
+ return unless timestamp = first_timestamp
92
+ delay = Clock.now - timestamp
93
+ delay > leeway ? delay : nil
94
+ end
95
+
96
+ # Wait until the earliest timestamp is reached without removing its value.
97
+ # @param timeout [Numeric, nil] maximum number of seconds to wait
98
+ # @return [Boolean] whether a value is ready
99
+ def wait_pop(timeout: nil) # rubocop:disable Naming/PredicateMethod
100
+ !UNDEFINED.equal?(wait_for_timestamp(timeout_at(timeout)))
101
+ end
102
+
103
+ # Delete the oldest matching value at the exact time.
104
+ # @param value [BasicObject] the value to delete
105
+ # @param at [Numeric, Time] the exact time to search
106
+ # @param compare_by_identity [Boolean] compare values by identity instead of equality
107
+ # @return [Boolean] whether a value was deleted
108
+ def delete(value, at:, compare_by_identity: false)
109
+ delete_from_storage(Clock.at(at), value, compare_by_identity:)
110
+ end
111
+
112
+ private
113
+
114
+ def wait_for_timestamp(deadline)
115
+ while true
116
+ generation = internal_signal.generation
117
+ timestamp = internal_queue.peek_priority
118
+ wake_after = nil
119
+ if timestamp
120
+ delay = timestamp - Clock.now
121
+ return timestamp unless delay.positive?
122
+ wake_after = delay if delay.finite?
123
+ end
124
+
125
+ remaining = remaining_timeout(deadline)
126
+
127
+ wait_for = wake_after && remaining ?
128
+ (wake_after < remaining ? wake_after : remaining) :
129
+ wake_after || remaining
130
+ changed = internal_signal.wait(generation, timeout: wait_for)
131
+ return UNDEFINED if !changed && deadline && remaining_timeout(deadline).zero?
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,269 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Abstract
7
+ # @abstract Superclass for all tree map implementations.
8
+ #
9
+ # You can think of a tree map as a sorted hash (sorted by key).
10
+ # Under the hood, tree maps are implemented as a balanced binary search tree.
11
+ #
12
+ # This means lookups, insertions, and deletions are O(log n) operations (vs O(1) for a hash map).
13
+ # This is much slower than a hash map, but much faster than ad hoc sorting of the map.
14
+ class TreeMap < Map
15
+ include DuplicableMap
16
+
17
+ # @note Subclasses may accept additional, optional arguments (usually keyword arguments) to configure the map.
18
+ # @param entries [Hash, Array<Array(BasicObject, BasicObject)>, Map, #each, nil]
19
+ # Optional initial entries for the map. Needs to implement #each and yield key-value pairs.
20
+ # If nil, the map will be empty.
21
+ # @!macro key_normalization
22
+ def initialize(entries = nil, normalize_keys: nil, **keyword_entries)
23
+ unless keyword_entries.empty?
24
+ raise ArgumentError, "entries given as both positional and keyword arguments" unless entries.nil?
25
+ entries = keyword_entries
26
+ end
27
+ entries = convert_entries(entries)
28
+ @map = new_tree_map
29
+ @key_locks = new_key_locks
30
+ restoring = Internal::KeyNormalizer.restoration?(normalize_keys)
31
+ normalizer = Internal::KeyNormalizer.build(
32
+ normalize_keys,
33
+ shareable: normalize_keys && Internal::KeyNormalizer.shareable_target?(self),
34
+ )
35
+ Internal::KeyNormalizer.install(self, normalizer, Internal::KeyNormalizer::TreeOperations) unless restoring
36
+ entries&.each { self[_1] = _2 }
37
+ Internal::KeyNormalizer.install(self, normalizer, Internal::KeyNormalizer::TreeOperations) if restoring
38
+ super()
39
+ end
40
+
41
+ # @api private
42
+ def transaction_wrapper(transaction)
43
+ transaction.enlist(transaction_key_locks)
44
+ manager = @manager if defined?(@manager)
45
+ Transaction::TreeMap.new(transaction, self, internal_map, manager:)
46
+ end
47
+
48
+ # (see Map#[])
49
+ def [](key) = unwrap_value(internal_map[prepare_key(key)])
50
+
51
+ # (see Map#[]=)
52
+ def []=(key, value)
53
+ key = internal_map.prepare_key(prepare_key(key))
54
+ with_key_lock(key) { internal_map[key] = wrap_value(value) }
55
+ value
56
+ end
57
+
58
+ # Return an existing value, or store the block result for an absent key.
59
+ # Concurrent callers for equally ordered keys share one initialization.
60
+ # The block runs without holding the map's structural lock. Other keys
61
+ # remain accessible. Assigning the same key waits for initialization.
62
+ # Deletion or clearing can precede a pending initialization's insertion.
63
+ # Unsafe maps require callers to provide their own synchronization.
64
+ # @param key [BasicObject] The key to retrieve or initialize.
65
+ # @yieldreturn [BasicObject] The value to store.
66
+ # @return [BasicObject] The existing or newly stored value.
67
+ # @raise [LocalJumpError] If no block is given, even when the key exists.
68
+ # @raise [ThreadError] If initialization recursively accesses its own gate.
69
+ def store_if_absent(key)
70
+ raise LocalJumpError, "no block given" unless block_given?
71
+
72
+ map = internal_map
73
+ key = map.prepare_key(prepare_key(key))
74
+ found = true
75
+ existing = map.fetch(key) { found = false }
76
+ return unwrap_value(existing) if found
77
+
78
+ with_key_lock(key) do
79
+ stored = map.fetch(key) do
80
+ value = yield
81
+ wrapped = wrap_value(value)
82
+ map[key] = wrapped
83
+ return unwrap_value(wrapped)
84
+ end
85
+ unwrap_value(stored)
86
+ end
87
+ end
88
+
89
+ # (see Map#delete)
90
+ def delete(key) = unwrap_value(internal_map.delete(prepare_key(key)))
91
+
92
+ # (see Map#empty?)
93
+ def empty? = internal_map.empty?
94
+
95
+ # (see Map#fetch)
96
+ def fetch(*arguments)
97
+ unless arguments.length.between?(1, 2)
98
+ raise ArgumentError, "wrong number of arguments (given #{arguments.length}, expected 1..2)"
99
+ end
100
+
101
+ key, default = arguments
102
+ key = prepare_key(key)
103
+ warn "block supersedes default value argument", uplevel: 1 if block_given? && arguments.length == 2
104
+ value = internal_map.fetch(key) do
105
+ return yield(key) if block_given?
106
+ return default if arguments.length == 2
107
+ raise KeyError.new("key not found: #{key.inspect}", receiver: self, key: key)
108
+ end
109
+ unwrap_value(value)
110
+ end
111
+
112
+ # Return the smallest key according to the map's ordering.
113
+ # @return [BasicObject, nil] The first key, or nil if the map is empty.
114
+ def first_key = internal_map.first_key
115
+
116
+ # (see Map#getkey)
117
+ def getkey(key) = internal_map.getkey(prepare_key(key))
118
+
119
+ # (see Map#key?)
120
+ def key?(key) = internal_map.key?(prepare_key(key))
121
+
122
+ # Return the largest key according to the map's ordering.
123
+ # @return [BasicObject, nil] The last key, or nil if the map is empty.
124
+ def last_key = internal_map.last_key
125
+
126
+ # (see Map#size)
127
+ def length = internal_map.length
128
+
129
+ # Remove and return the entry with the largest key according to the map's ordering.
130
+ # @return [Array(BasicObject, BasicObject), nil] The last key-value pair, or nil if the map is empty.
131
+ def pop
132
+ pair = internal_map.pop
133
+ [pair.first, unwrap_value(pair.last)] if pair
134
+ end
135
+
136
+ # Remove and return the entry with the smallest key according to the map's ordering.
137
+ # @return [Array(BasicObject, BasicObject), nil] The first key-value pair, or nil if the map is empty.
138
+ def shift
139
+ pair = internal_map.shift
140
+ [pair.first, unwrap_value(pair.last)] if pair
141
+ end
142
+
143
+ # (see Map#size)
144
+ def size = internal_map.size
145
+
146
+ # Remove all entries from the map.
147
+ # @return [self]
148
+ def clear
149
+ internal_map.clear
150
+ self
151
+ end
152
+
153
+ # Iterate over the map's key-value pairs.
154
+ # Order is guaranteed to be from smallest to largest key according.
155
+ #
156
+ # @overload each
157
+ # @yield [pair] Called once for each entry.
158
+ # @yieldparam pair [Array<BasicObject>] A two-element `[key, value]` pair.
159
+ # @return [self]
160
+ # @overload each
161
+ # @return [Enumerator] An enumerator over two-element `[key, value]` pairs.
162
+ def each
163
+ return enum_for(__method__) unless block_given?
164
+ internal_map.each { |key, value| yield [key, unwrap_value(value)] }
165
+ self
166
+ end
167
+
168
+ # Iterate incrementally in key order without allocating a full snapshot.
169
+ # Deletion and value replacement between yields are permitted. Insertion
170
+ # or clearing can invalidate traversal and raise RuntimeError. No tree
171
+ # lock is held while the block runs.
172
+ # @api private
173
+ def each_live
174
+ return enum_for(__method__) { size } unless block_given?
175
+ internal_map.each_live { |key, value| yield [key, unwrap_value(value)] }
176
+ self
177
+ end
178
+
179
+ alias each_pair each
180
+
181
+ # Iterate over the keys currently stored in the map.
182
+ # Keys are yielded from smallest to largest.
183
+ #
184
+ # @overload each_key
185
+ # @yield [key] Called once for each stored key.
186
+ # @yieldparam key [BasicObject] A stored key.
187
+ # @return [self]
188
+ # @overload each_key
189
+ # @return [Enumerator] An enumerator over the stored keys.
190
+ def each_key
191
+ return enum_for(__method__) unless block_given?
192
+ each { |key, _| yield key }
193
+ self
194
+ end
195
+
196
+ # Iterate over the values currently stored in the map.
197
+ # Values are yielded in the order of their corresponding keys (from smallest to largest).
198
+ #
199
+ # @overload each_value
200
+ # @yield [value] Called once for each stored value.
201
+ # @yieldparam value [BasicObject] A stored value.
202
+ # @return [self]
203
+ # @overload each_value
204
+ # @return [Enumerator] An enumerator over the stored values.
205
+ def each_value
206
+ return enum_for(__method__) unless block_given?
207
+ each { |_, value| yield value }
208
+ self
209
+ end
210
+
211
+ # Return the keys currently stored in the map.
212
+ # The result is frozen and ordered from smallest to largest key.
213
+ # @return [Array<BasicObject>] The keys currently stored in the map, in order from smallest to largest.
214
+ def keys = each_key.to_a.freeze
215
+
216
+ # Return the values currently stored in the map.
217
+ # The result is frozen and ordered according to the order of their corresponding keys (from smallest to largest).
218
+ # @return [Array<BasicObject>] The values currently stored in the map.
219
+ def values = each_value.to_a.freeze
220
+
221
+ # TreeMap keys always have to be Ractor-shareable.
222
+ # Mutable strings are accepted however and will be converted to an immutable string.
223
+ # @return [true]
224
+ def shareable_keys? = true
225
+
226
+ # TreeMap keys are compared by their ordering, never by identity.
227
+ # @return [false]
228
+ def compare_keys_by_identity? = false
229
+
230
+ # TreeMap values are compared by equality, never by identity.
231
+ # @return [false]
232
+ def compare_values_by_identity? = false
233
+
234
+ protected
235
+
236
+ def transaction_key_locks = @key_locks
237
+
238
+ private
239
+
240
+ def copy_map_backend(source, empty: false)
241
+ copied = source.class.new
242
+ source.each { |key, value| copied[key] = value } unless empty
243
+ copied
244
+ end
245
+
246
+ def install_copied_map(map)
247
+ super
248
+ @key_locks = new_key_locks
249
+ end
250
+
251
+ def each_for_inspect(&) = each(&)
252
+
253
+ def prepare_key(key)
254
+ return key if String === key || Ractor.shareable?(key)
255
+ raise Ractor::IsolationError, "key must be Ractor-shareable"
256
+ end
257
+
258
+ def new_key_locks = Internal::OrderedKeyLockMap.new
259
+ def with_key_lock(key, &) = @key_locks.synchronize(key, &)
260
+
261
+ # simplecov:disable
262
+ def new_tree_map(...)
263
+ raise "subclass failed to implement #new_tree_map" unless instance_of?(TreeMap)
264
+ raise NoMethodError, "Farce::Abstract::TreeMap should not be instantiated directly. Use a subclass instead."
265
+ end
266
+ # simplecov:enable
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Abstract
7
+ # Mixin to indicate {#value} can safely be called on an object.
8
+ #
9
+ # @!method value
10
+ # @abstract
11
+ # Can be called multiple times without argument.
12
+ # Some subclasses may allow optional arguments, especially a `timeout` keyword argument.
13
+ # This method may block.
14
+ # @return [BasicObject] The underlying value of the object.
15
+ #
16
+ # @abstract
17
+ module Value
18
+ Internal::Atom.include(self)
19
+
20
+ # Unwraps nested {Value} objects to get the underlying value.
21
+ #
22
+ # @example Nested unwrapping
23
+ # MyValue = Data.define(:value) { include Farce::Abstract::Value }
24
+ # inner = MyValue.new(42)
25
+ # outer = MyValue.new(inner)
26
+ # outer.unwrap # => 42
27
+ #
28
+ # @example Cycle detection
29
+ # MyValue = Struct.new(:name, :value) { include Farce::Abstract::Value }
30
+ #
31
+ # a = MyValue.new("A")
32
+ # b = MyValue.new("B", a)
33
+ # c = MyValue.new("C", a)
34
+ # a.value = b
35
+ #
36
+ # c.unwrap # => nil
37
+ # c.unwrap("default") # => "default"
38
+ #
39
+ # # RuntimeError: cycle detected starting at A
40
+ # c.unwrap { raise "cycle detected starting at #{value.name}" }
41
+ #
42
+ # @overload unwrap(default = nil)
43
+ # @param [BasicObject] default The value to return if a cycle is detected.
44
+ #
45
+ # @overload unwrap
46
+ # @yield [value] Block to call if a cycle is detected.
47
+ # @yieldparam [Value] value The value that has been determined to be the start of the cycle.
48
+ # @yieldreturn [BasicObject] The value to return if a cycle is detected
49
+ #
50
+ # @return [BasicObject] The underlying value of the object, or a default value based on the argument or block.
51
+ def unwrap(default = nil)
52
+ value = value()
53
+ return value unless value.is_a?(Value)
54
+
55
+ seen = ::Set.new.compare_by_identity
56
+ seen << self
57
+
58
+ while value.is_a?(Value)
59
+ return block_given? ? yield(value) : default if seen.include?(value)
60
+ seen << value
61
+ value = value.value
62
+ end
63
+
64
+ value
65
+ end
66
+ end
67
+ end
68
+ end