farce 0.0.1.alpha2-x86_64-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (423) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +26 -0
  3. data/CONTRIBUTING.md +71 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +1524 -0
  6. data/SECURITY.md +10 -0
  7. data/docs/benchmarks.md +185 -0
  8. data/docs/gems/dry-types.md +290 -0
  9. data/docs/gems/msgpack.md +70 -0
  10. data/docs/gems/ractor-shim.md +63 -0
  11. data/docs/modes.md +628 -0
  12. data/docs/scopes.md +649 -0
  13. data/docs/variants.md +346 -0
  14. data/ext/ext_helper.rb +20 -0
  15. data/ext/farce/README.md +21 -0
  16. data/ext/farce/atom.c +1023 -0
  17. data/ext/farce/bounded_map.c +1683 -0
  18. data/ext/farce/containers.h +77 -0
  19. data/ext/farce/counter.c +399 -0
  20. data/ext/farce/darwin.c +100 -0
  21. data/ext/farce/depend +12 -0
  22. data/ext/farce/dict.c +1523 -0
  23. data/ext/farce/dict.h +152 -0
  24. data/ext/farce/drivers.c +237 -0
  25. data/ext/farce/exchanger.c +299 -0
  26. data/ext/farce/extconf.rb +99 -0
  27. data/ext/farce/farce.c +359 -0
  28. data/ext/farce/flag.c +288 -0
  29. data/ext/farce/io.c +338 -0
  30. data/ext/farce/lock.c +510 -0
  31. data/ext/farce/map.c +2240 -0
  32. data/ext/farce/priority_queue.c +2056 -0
  33. data/ext/farce/queue.c +1059 -0
  34. data/ext/farce/reactor.c +820 -0
  35. data/ext/farce/reactor.h +103 -0
  36. data/ext/farce/shareable.h +31 -0
  37. data/ext/farce/signal.c +350 -0
  38. data/ext/farce/transaction.c +354 -0
  39. data/ext/farce/transaction.h +40 -0
  40. data/ext/farce/tree_map.c +1953 -0
  41. data/ext/farce/trie.c +2020 -0
  42. data/ext/farce/unshareable.c +155 -0
  43. data/ext/farce/unshared_io_pool.h +234 -0
  44. data/ext/farce/unshared_signal.c +263 -0
  45. data/ext/farce/unshared_wait.h +193 -0
  46. data/ext/farce/unsupported.c +6 -0
  47. data/ext/farce/vector.c +1195 -0
  48. data/ext/farce/weak_map.c +1714 -0
  49. data/ext/java/org/farce/BoundedMap.java +394 -0
  50. data/ext/java/org/farce/FiberScheduler.java +141 -0
  51. data/ext/java/org/farce/PriorityKey.java +45 -0
  52. data/ext/java/org/farce/PriorityQueue.java +373 -0
  53. data/ext/java/org/farce/QueueSignal.java +28 -0
  54. data/ext/rebind/README.md +14 -0
  55. data/ext/rebind/extconf.rb +10 -0
  56. data/ext/rebind/rebind.c +186 -0
  57. data/lib/farce/_yard/internal.rb +13 -0
  58. data/lib/farce/_yard/macros.rb +61 -0
  59. data/lib/farce/_yard/ractor.rb +46 -0
  60. data/lib/farce/abstract/atom.rb +186 -0
  61. data/lib/farce/abstract/bounded_map.rb +232 -0
  62. data/lib/farce/abstract/collection.rb +151 -0
  63. data/lib/farce/abstract/concurrent_map.rb +381 -0
  64. data/lib/farce/abstract/counter.rb +193 -0
  65. data/lib/farce/abstract/duplicable_map.rb +229 -0
  66. data/lib/farce/abstract/exchanger.rb +26 -0
  67. data/lib/farce/abstract/flag.rb +71 -0
  68. data/lib/farce/abstract/lazy.rb +115 -0
  69. data/lib/farce/abstract/lease.rb +104 -0
  70. data/lib/farce/abstract/lease_map.rb +261 -0
  71. data/lib/farce/abstract/lease_pool.rb +91 -0
  72. data/lib/farce/abstract/lfu_map.rb +20 -0
  73. data/lib/farce/abstract/lru_map.rb +25 -0
  74. data/lib/farce/abstract/map.rb +345 -0
  75. data/lib/farce/abstract/molecule.rb +245 -0
  76. data/lib/farce/abstract/port.rb +74 -0
  77. data/lib/farce/abstract/priority_queue.rb +117 -0
  78. data/lib/farce/abstract/queue.rb +269 -0
  79. data/lib/farce/abstract/scheduler.rb +111 -0
  80. data/lib/farce/abstract/set.rb +910 -0
  81. data/lib/farce/abstract/sorted_set.rb +172 -0
  82. data/lib/farce/abstract/timer_queue.rb +136 -0
  83. data/lib/farce/abstract/tree_map.rb +269 -0
  84. data/lib/farce/abstract/value.rb +68 -0
  85. data/lib/farce/abstract/vector.rb +1126 -0
  86. data/lib/farce/abstract/weak_atom.rb +32 -0
  87. data/lib/farce/abstract/weak_key_map.rb +12 -0
  88. data/lib/farce/abstract/weak_map.rb +13 -0
  89. data/lib/farce/abstract/weak_set.rb +12 -0
  90. data/lib/farce/abstract/weak_value_map.rb +12 -0
  91. data/lib/farce/abstract.rb +17 -0
  92. data/lib/farce/atom.rb +293 -0
  93. data/lib/farce/class_mirror.rb +87 -0
  94. data/lib/farce/clock.rb +121 -0
  95. data/lib/farce/config.rb +229 -0
  96. data/lib/farce/counter.rb +71 -0
  97. data/lib/farce/deduper.rb +122 -0
  98. data/lib/farce/engine/jruby/bounded_map.rb +314 -0
  99. data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
  100. data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
  101. data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
  102. data/lib/farce/engine/jruby/map.rb +505 -0
  103. data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
  104. data/lib/farce/engine/jruby/signal.rb +147 -0
  105. data/lib/farce/engine/jruby.rb +63 -0
  106. data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
  107. data/lib/farce/engine/jvm/counter.rb +102 -0
  108. data/lib/farce/engine/jvm/extension.rb +32 -0
  109. data/lib/farce/engine/jvm/farce.jar +0 -0
  110. data/lib/farce/engine/jvm/flag.rb +79 -0
  111. data/lib/farce/engine/jvm/priority_queue.rb +217 -0
  112. data/lib/farce/engine/jvm/tree_map.rb +350 -0
  113. data/lib/farce/engine/jvm/types.rb +180 -0
  114. data/lib/farce/engine/jvm.rb +19 -0
  115. data/lib/farce/engine/ruby/3.4/farce.so +0 -0
  116. data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
  117. data/lib/farce/engine/ruby/3.4/port.rb +186 -0
  118. data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
  119. data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
  120. data/lib/farce/engine/ruby/3.4/rebind.so +0 -0
  121. data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
  122. data/lib/farce/engine/ruby/4.0/farce.so +0 -0
  123. data/lib/farce/engine/ruby/4.0/port.rb +19 -0
  124. data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
  125. data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
  126. data/lib/farce/engine/ruby/4.0/rebind.so +0 -0
  127. data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
  128. data/lib/farce/engine/ruby/4.1/port.rb +21 -0
  129. data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
  130. data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
  131. data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
  132. data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
  133. data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
  134. data/lib/farce/engine/ruby/shared/lease.rb +26 -0
  135. data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
  136. data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
  137. data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
  138. data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
  139. data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
  140. data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
  141. data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
  142. data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
  143. data/lib/farce/engine/ruby/shared/vault.rb +144 -0
  144. data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
  145. data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
  146. data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
  147. data/lib/farce/engine/ruby.rb +130 -0
  148. data/lib/farce/engine/shared/atom.rb +10 -0
  149. data/lib/farce/engine/shared/exchanger.rb +130 -0
  150. data/lib/farce/engine/shared/identity_key.rb +22 -0
  151. data/lib/farce/engine/shared/lease.rb +10 -0
  152. data/lib/farce/engine/shared/lease_pool.rb +10 -0
  153. data/lib/farce/engine/shared/main_scheduler.rb +20 -0
  154. data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
  155. data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
  156. data/lib/farce/engine/shared/port.rb +44 -0
  157. data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
  158. data/lib/farce/engine/shared/proxy_owner.rb +43 -0
  159. data/lib/farce/engine/shared/queue.rb +233 -0
  160. data/lib/farce/engine/shared/ractor_methods.rb +73 -0
  161. data/lib/farce/engine/shared/rebindable.rb +15 -0
  162. data/lib/farce/engine/shared/strict_atom.rb +73 -0
  163. data/lib/farce/engine/shared/strict_map.rb +117 -0
  164. data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
  165. data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
  166. data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
  167. data/lib/farce/engine/shared/trie.rb +317 -0
  168. data/lib/farce/engine/shared/trie_builder.rb +199 -0
  169. data/lib/farce/engine/shared/unshareable.rb +14 -0
  170. data/lib/farce/engine/shared/unshared_atom.rb +256 -0
  171. data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
  172. data/lib/farce/engine/shared/unshared_queue.rb +18 -0
  173. data/lib/farce/engine/shared/unshared_signal.rb +21 -0
  174. data/lib/farce/engine/shared/unshared_vector.rb +377 -0
  175. data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
  176. data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
  177. data/lib/farce/engine/shared/vault.rb +31 -0
  178. data/lib/farce/engine/shared/vector.rb +83 -0
  179. data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
  180. data/lib/farce/engine/shared/weak_atom.rb +20 -0
  181. data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
  182. data/lib/farce/engine/shared/weak_map/index.rb +249 -0
  183. data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
  184. data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
  185. data/lib/farce/engine/shared.rb +63 -0
  186. data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
  187. data/lib/farce/engine/truffleruby/lock.rb +121 -0
  188. data/lib/farce/engine/truffleruby/map.rb +656 -0
  189. data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
  190. data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
  191. data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
  192. data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
  193. data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
  194. data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
  195. data/lib/farce/engine/truffleruby/signal.rb +77 -0
  196. data/lib/farce/engine/truffleruby.rb +148 -0
  197. data/lib/farce/envelope.rb +335 -0
  198. data/lib/farce/error.rb +35 -0
  199. data/lib/farce/exchanger.rb +41 -0
  200. data/lib/farce/flag.rb +27 -0
  201. data/lib/farce/integrations/active_support/blank.rb +68 -0
  202. data/lib/farce/integrations/active_support/clock.rb +17 -0
  203. data/lib/farce/integrations/active_support/duplicable.rb +78 -0
  204. data/lib/farce/integrations/active_support/map.rb +175 -0
  205. data/lib/farce/integrations/active_support/set.rb +60 -0
  206. data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
  207. data/lib/farce/integrations/active_support/vector.rb +231 -0
  208. data/lib/farce/integrations/active_support.rb +9 -0
  209. data/lib/farce/integrations/activesupport.rb +5 -0
  210. data/lib/farce/integrations/bson.rb +108 -0
  211. data/lib/farce/integrations/cbor.rb +51 -0
  212. data/lib/farce/integrations/concurrent.rb +112 -0
  213. data/lib/farce/integrations/dry-types.rb +5 -0
  214. data/lib/farce/integrations/dry_types.rb +694 -0
  215. data/lib/farce/integrations/json.rb +7 -0
  216. data/lib/farce/integrations/msgpack.rb +112 -0
  217. data/lib/farce/integrations/oj.rb +69 -0
  218. data/lib/farce/integrations/psych.rb +191 -0
  219. data/lib/farce/integrations/ractor-sharing.rb +5 -0
  220. data/lib/farce/integrations/ractor-tmvar.rb +5 -0
  221. data/lib/farce/integrations/ractor_sharing.rb +172 -0
  222. data/lib/farce/integrations/ractor_tmvar.rb +64 -0
  223. data/lib/farce/integrations/shared/to_json.rb +42 -0
  224. data/lib/farce/integrations/sorted_set.rb +11 -0
  225. data/lib/farce/integrations/weakref.rb +38 -0
  226. data/lib/farce/integrations/yajl.rb +10 -0
  227. data/lib/farce/integrations.rb +156 -0
  228. data/lib/farce/internal/_frozen_config.rb +11 -0
  229. data/lib/farce/internal/autoloads.rb +47 -0
  230. data/lib/farce/internal/blocking_priority_queue.rb +122 -0
  231. data/lib/farce/internal/converter.rb +106 -0
  232. data/lib/farce/internal/copyable.rb +31 -0
  233. data/lib/farce/internal/delegation.rb +20 -0
  234. data/lib/farce/internal/external_transaction.rb +59 -0
  235. data/lib/farce/internal/fake_ractor.rb +179 -0
  236. data/lib/farce/internal/freeze.rb +118 -0
  237. data/lib/farce/internal/inspect.rb +157 -0
  238. data/lib/farce/internal/key_lock_map.rb +29 -0
  239. data/lib/farce/internal/key_normalizer.rb +289 -0
  240. data/lib/farce/internal/lease_initialization.rb +115 -0
  241. data/lib/farce/internal/lease_map.rb +441 -0
  242. data/lib/farce/internal/lease_pool_state.rb +228 -0
  243. data/lib/farce/internal/lease_state.rb +342 -0
  244. data/lib/farce/internal/lease_waiting.rb +13 -0
  245. data/lib/farce/internal/managed_queue.rb +26 -0
  246. data/lib/farce/internal/map_value_modes.rb +227 -0
  247. data/lib/farce/internal/marshal_support.rb +227 -0
  248. data/lib/farce/internal/mixin.rb +20 -0
  249. data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
  250. data/lib/farce/internal/noncopyable.rb +17 -0
  251. data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
  252. data/lib/farce/internal/pool_supervisor.rb +41 -0
  253. data/lib/farce/internal/pool_worker.rb +61 -0
  254. data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
  255. data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
  256. data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
  257. data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
  258. data/lib/farce/internal/portable_transaction.rb +164 -0
  259. data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
  260. data/lib/farce/internal/reservation_waiting.rb +24 -0
  261. data/lib/farce/internal/scheduled_task.rb +48 -0
  262. data/lib/farce/internal/scheduler_io.rb +171 -0
  263. data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
  264. data/lib/farce/internal/select_scheduler.rb +235 -0
  265. data/lib/farce/internal/storage.rb +162 -0
  266. data/lib/farce/internal/strict_lease.rb +30 -0
  267. data/lib/farce/internal/strict_lease_map.rb +20 -0
  268. data/lib/farce/internal/strict_lease_pool.rb +29 -0
  269. data/lib/farce/internal/thread_pool.rb +166 -0
  270. data/lib/farce/internal/transaction_conflict.rb +9 -0
  271. data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
  272. data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
  273. data/lib/farce/internal/undefined.rb +22 -0
  274. data/lib/farce/internal/unshared_lease.rb +29 -0
  275. data/lib/farce/internal/unshared_lease_pool.rb +34 -0
  276. data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
  277. data/lib/farce/internal/value_serialization.rb +13 -0
  278. data/lib/farce/internal/weak_map_value_modes.rb +58 -0
  279. data/lib/farce/internal/weak_mode_manager.rb +26 -0
  280. data/lib/farce/internal.rb +129 -0
  281. data/lib/farce/lazy.rb +100 -0
  282. data/lib/farce/lazy_ref.rb +40 -0
  283. data/lib/farce/lease.rb +28 -0
  284. data/lib/farce/lease_map.rb +34 -0
  285. data/lib/farce/lease_pool.rb +29 -0
  286. data/lib/farce/lfu_map.rb +53 -0
  287. data/lib/farce/local/atom.rb +23 -0
  288. data/lib/farce/local/counter.rb +88 -0
  289. data/lib/farce/local/flag.rb +65 -0
  290. data/lib/farce/local/lazy.rb +38 -0
  291. data/lib/farce/local/lazy_ref.rb +36 -0
  292. data/lib/farce/local/lease.rb +77 -0
  293. data/lib/farce/local/lease_map.rb +80 -0
  294. data/lib/farce/local/lease_pool.rb +38 -0
  295. data/lib/farce/local/lfu_map.rb +55 -0
  296. data/lib/farce/local/lru_map.rb +62 -0
  297. data/lib/farce/local/map.rb +47 -0
  298. data/lib/farce/local/molecule.rb +45 -0
  299. data/lib/farce/local/priority_queue.rb +53 -0
  300. data/lib/farce/local/queue.rb +32 -0
  301. data/lib/farce/local/scoped.rb +166 -0
  302. data/lib/farce/local/set.rb +18 -0
  303. data/lib/farce/local/sorted_set.rb +50 -0
  304. data/lib/farce/local/timer_queue.rb +41 -0
  305. data/lib/farce/local/tree_map.rb +47 -0
  306. data/lib/farce/local/vector.rb +30 -0
  307. data/lib/farce/local/weak_atom.rb +23 -0
  308. data/lib/farce/local/weak_key_map.rb +39 -0
  309. data/lib/farce/local/weak_map.rb +39 -0
  310. data/lib/farce/local/weak_set.rb +18 -0
  311. data/lib/farce/local/weak_value_map.rb +39 -0
  312. data/lib/farce/local.rb +35 -0
  313. data/lib/farce/lock.rb +54 -0
  314. data/lib/farce/lru_map.rb +63 -0
  315. data/lib/farce/map.rb +58 -0
  316. data/lib/farce/mode_manager.rb +142 -0
  317. data/lib/farce/molecule.rb +60 -0
  318. data/lib/farce/mutable.rb +171 -0
  319. data/lib/farce/pool.rb +332 -0
  320. data/lib/farce/port.rb +134 -0
  321. data/lib/farce/priority_queue.rb +70 -0
  322. data/lib/farce/proxy/register.rb +101 -0
  323. data/lib/farce/proxy/supervisor.rb +137 -0
  324. data/lib/farce/proxy/wrapper.rb +49 -0
  325. data/lib/farce/proxy.rb +291 -0
  326. data/lib/farce/queue.rb +60 -0
  327. data/lib/farce/ractor.rb +269 -0
  328. data/lib/farce/read_write_lock.rb +256 -0
  329. data/lib/farce/reference.rb +158 -0
  330. data/lib/farce/resolv/dns.rb +42 -0
  331. data/lib/farce/resolv.rb +85 -0
  332. data/lib/farce/scheduler.rb +536 -0
  333. data/lib/farce/set.rb +39 -0
  334. data/lib/farce/shareable.rb +150 -0
  335. data/lib/farce/signal.rb +97 -0
  336. data/lib/farce/sorted_set.rb +36 -0
  337. data/lib/farce/strict/atom.rb +34 -0
  338. data/lib/farce/strict/counter.rb +10 -0
  339. data/lib/farce/strict/exchanger.rb +25 -0
  340. data/lib/farce/strict/flag.rb +10 -0
  341. data/lib/farce/strict/lazy.rb +26 -0
  342. data/lib/farce/strict/lazy_ref.rb +26 -0
  343. data/lib/farce/strict/lease.rb +27 -0
  344. data/lib/farce/strict/lease_map.rb +33 -0
  345. data/lib/farce/strict/lease_pool.rb +28 -0
  346. data/lib/farce/strict/lfu_map.rb +27 -0
  347. data/lib/farce/strict/lru_map.rb +28 -0
  348. data/lib/farce/strict/map.rb +54 -0
  349. data/lib/farce/strict/molecule.rb +16 -0
  350. data/lib/farce/strict/port.rb +40 -0
  351. data/lib/farce/strict/priority_queue.rb +20 -0
  352. data/lib/farce/strict/queue.rb +17 -0
  353. data/lib/farce/strict/set.rb +14 -0
  354. data/lib/farce/strict/sorted_set.rb +19 -0
  355. data/lib/farce/strict/timer_queue.rb +13 -0
  356. data/lib/farce/strict/tree_map.rb +27 -0
  357. data/lib/farce/strict/vector.rb +24 -0
  358. data/lib/farce/strict/weak_atom.rb +31 -0
  359. data/lib/farce/strict/weak_key_map.rb +49 -0
  360. data/lib/farce/strict/weak_map.rb +49 -0
  361. data/lib/farce/strict/weak_set.rb +14 -0
  362. data/lib/farce/strict/weak_value_map.rb +48 -0
  363. data/lib/farce/strict.rb +28 -0
  364. data/lib/farce/system.rb +40 -0
  365. data/lib/farce/thread_scheduler.rb +70 -0
  366. data/lib/farce/timer_queue.rb +66 -0
  367. data/lib/farce/transaction/atom.rb +73 -0
  368. data/lib/farce/transaction/map.rb +25 -0
  369. data/lib/farce/transaction/map_operations.rb +143 -0
  370. data/lib/farce/transaction/molecule.rb +90 -0
  371. data/lib/farce/transaction/mutable.rb +61 -0
  372. data/lib/farce/transaction/set.rb +17 -0
  373. data/lib/farce/transaction/set_operations.rb +48 -0
  374. data/lib/farce/transaction/sorted_set.rb +18 -0
  375. data/lib/farce/transaction/tree_map.rb +78 -0
  376. data/lib/farce/transaction/vector.rb +139 -0
  377. data/lib/farce/transaction/wrapper.rb +202 -0
  378. data/lib/farce/transaction.rb +343 -0
  379. data/lib/farce/tree_map.rb +56 -0
  380. data/lib/farce/unsafe/lfu_map.rb +36 -0
  381. data/lib/farce/unsafe/lru_map.rb +36 -0
  382. data/lib/farce/unsafe/tree_map.rb +21 -0
  383. data/lib/farce/unsafe.rb +29 -0
  384. data/lib/farce/unshareable.rb +67 -0
  385. data/lib/farce/unshared/atom.rb +24 -0
  386. data/lib/farce/unshared/counter.rb +10 -0
  387. data/lib/farce/unshared/flag.rb +10 -0
  388. data/lib/farce/unshared/lazy.rb +38 -0
  389. data/lib/farce/unshared/lazy_ref.rb +26 -0
  390. data/lib/farce/unshared/lease.rb +27 -0
  391. data/lib/farce/unshared/lease_map.rb +26 -0
  392. data/lib/farce/unshared/lease_pool.rb +25 -0
  393. data/lib/farce/unshared/lfu_map.rb +20 -0
  394. data/lib/farce/unshared/lru_map.rb +20 -0
  395. data/lib/farce/unshared/map.rb +49 -0
  396. data/lib/farce/unshared/molecule.rb +16 -0
  397. data/lib/farce/unshared/priority_queue.rb +16 -0
  398. data/lib/farce/unshared/queue.rb +27 -0
  399. data/lib/farce/unshared/set.rb +14 -0
  400. data/lib/farce/unshared/sorted_set.rb +28 -0
  401. data/lib/farce/unshared/timer_queue.rb +16 -0
  402. data/lib/farce/unshared/tree_map.rb +21 -0
  403. data/lib/farce/unshared/vector.rb +19 -0
  404. data/lib/farce/unshared/weak_atom.rb +31 -0
  405. data/lib/farce/unshared/weak_key_map.rb +44 -0
  406. data/lib/farce/unshared/weak_map.rb +44 -0
  407. data/lib/farce/unshared/weak_set.rb +14 -0
  408. data/lib/farce/unshared/weak_value_map.rb +43 -0
  409. data/lib/farce/unshared.rb +28 -0
  410. data/lib/farce/vector.rb +228 -0
  411. data/lib/farce/version.rb +8 -0
  412. data/lib/farce/walker/definitions.rb +186 -0
  413. data/lib/farce/walker/modification.rb +355 -0
  414. data/lib/farce/walker.rb +319 -0
  415. data/lib/farce/weak_atom.rb +121 -0
  416. data/lib/farce/weak_key_map.rb +31 -0
  417. data/lib/farce/weak_map.rb +33 -0
  418. data/lib/farce/weak_ref.rb +67 -0
  419. data/lib/farce/weak_set.rb +82 -0
  420. data/lib/farce/weak_value.rb +195 -0
  421. data/lib/farce/weak_value_map.rb +32 -0
  422. data/lib/farce.rb +519 -0
  423. metadata +468 -0
@@ -0,0 +1,46 @@
1
+ return if true
2
+
3
+ # @!visibility private
4
+ class Ractor
5
+ end
6
+
7
+ module Farce
8
+ module Ractor
9
+ # Either `Ractor::Port` or a shim for it. It is recommended to use {Farce::Port Farce::Port} instead,
10
+ # which will always be a subclass of this class, but has added safety and functionality.
11
+ class Port
12
+ # Closes the port. Sending to a closed port is prohibited. Receiving is also prohibited if there are no
13
+ # messages in its message queue. Only the Ractor which created the port is allowed to close it.
14
+ # @return [void]
15
+ def close = super
16
+
17
+ # Checks it the port is closed.
18
+ # @return [Boolean] `true` if the port is closed, `false` otherwise.
19
+ # @see #close
20
+ def closed? = super
21
+
22
+ # @overload receive
23
+ # Receives a message from the port.
24
+ # @return [BasicObject] The received message.
25
+ # @overload receive(timeout: nil)
26
+ # Receives a message from the port. Blocks until a message is available or the timeout is reached.
27
+ # @note
28
+ # Use {Farce::Port Farce::Port} instead to guarantee a timeout argument on all Ruby implementations.
29
+ # @ruby CRuby 4.1+, JRuby, TruffleRuby
30
+ # @param timeout [Numeric, nil] The timeout in seconds, or `nil` for no timeout.
31
+ # @return [BasicObject, nil] The received message, or `nil` if the timeout has been reached.
32
+ #
33
+ # @return [BasicObject]
34
+ # @raise [Farce::Ractor::ClosedError] if the port is closed and there are no messages in the queue.
35
+ def receive = super
36
+
37
+ # Sends a message over the port.
38
+ # @param message [BasicObject] The message to send.
39
+ # @param move [Boolean] Whether to move the message to the Ractor if it isn't sharable.
40
+ # @return [self]
41
+ # @raise [Farce::Ractor::ClosedError] if the port is closed.
42
+ def send(message, move: false) = super
43
+ alias << send
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Abstract
7
+ # @abstract Common interface and behavior for atomic references.
8
+ #
9
+ # Concrete implementations decide how values are retained and transferred.
10
+ # A value may become `nil` without an explicit update when an implementation
11
+ # retains it weakly.
12
+ class Atom
13
+ include Internal::MarshalSupport::Atom
14
+ include Internal::Copyable
15
+ include Internal::Inspect
16
+ include Value
17
+ include Internal::ValueSerialization
18
+
19
+ # @api private
20
+ def transaction_wrapper(transaction) = Transaction::Atom.new(transaction, self, internal_atom)
21
+
22
+ # Whether comparisons use object identity instead of equality.
23
+ # @return [Boolean]
24
+ def compare_by_identity? = internal_atom.compare_by_identity?
25
+
26
+ # Return the current value without waiting for an update in progress.
27
+ # @return [BasicObject, nil] the current value
28
+ def value = internal_atom.value
29
+
30
+ # Store a new value.
31
+ # @param new_value [BasicObject, nil] the new value
32
+ # @return [BasicObject, nil] the new value
33
+ def value=(new_value)
34
+ store(new_value)
35
+ end
36
+
37
+ # Return the current value, waiting for any update in progress.
38
+ # @param timeout [Numeric, nil] the maximum number of seconds to wait
39
+ # @yield called when the timeout expires
40
+ # @return [BasicObject, nil] the current value or the fallback result
41
+ def get(timeout: nil, &) = internal_atom.get(timeout:, &)
42
+
43
+ # Store a new value, waiting for any update in progress.
44
+ # @param new_value [BasicObject, nil] the new value
45
+ # @param timeout [Numeric, nil] the maximum number of seconds to wait
46
+ # @yield called when the timeout expires
47
+ # @return [BasicObject, nil] the stored value or the fallback result
48
+ def store(new_value, timeout: nil, &) = internal_atom.store(new_value, timeout:, &)
49
+
50
+ # Replace the current value and return the previous value.
51
+ # @param new_value [BasicObject, nil] the new value
52
+ # @param timeout [Numeric, nil] the maximum number of seconds to wait
53
+ # @yield called when the timeout expires
54
+ # @return [BasicObject, nil] the previous value or the fallback result
55
+ def swap(new_value, timeout: nil, &) = internal_atom.swap(new_value, timeout:, &)
56
+
57
+ # Compute and store a value if the current value is nil.
58
+ # @param timeout [Numeric, nil] the maximum number of seconds to wait
59
+ # @yield computes the value to store when the current value is nil
60
+ # @yieldreturn [BasicObject, nil] the value to store
61
+ # @return [BasicObject, nil] the current or newly stored value, or nil when the timeout expires
62
+ def store_if_absent(timeout: nil, &) = internal_atom.store_if_absent(timeout:, &)
63
+
64
+ # Atomically replace the current value if it matches the expected value.
65
+ # @param expected [BasicObject, nil] the value to compare with the current value
66
+ # @param new_value [BasicObject, nil] the replacement value
67
+ # @param timeout [Numeric, nil] the maximum number of seconds to wait
68
+ # @return [Boolean] whether the value was replaced
69
+ def compare_and_set(expected, new_value, timeout: nil)
70
+ internal_atom.compare_and_set(expected, new_value, timeout:)
71
+ end
72
+
73
+ # Atomically replace the current value with the result of a block.
74
+ # @param timeout [Numeric, nil] the maximum number of seconds to wait
75
+ # @yield receives the current value and computes its replacement
76
+ # @yieldparam current [BasicObject, nil] the current value
77
+ # @yieldreturn [BasicObject, nil] the replacement value
78
+ # @return [BasicObject, nil] the replacement value, or nil when the timeout expires
79
+ def update(timeout: nil, &) = internal_atom.update(timeout:, &)
80
+
81
+ # Store an initial value if the current value is nil, otherwise replace it with the result of a block.
82
+ # @param initial_value [BasicObject, nil] the value to store when the current value is nil
83
+ # @param timeout [Numeric, nil] the maximum number of seconds to wait
84
+ # @yield receives a non-nil current value and computes its replacement
85
+ # @yieldparam current [BasicObject] the current value
86
+ # @yieldreturn [BasicObject, nil] the replacement value
87
+ # @return [BasicObject, nil] the replacement or initial value, or nil when the timeout expires
88
+ def upsert(initial_value, timeout: nil, &) = internal_atom.upsert(initial_value, timeout:, &)
89
+
90
+ # Wait until a block condition matches the current value.
91
+ # One timeout budget covers all checks and waits. The block is not interrupted.
92
+ # @yieldparam value [BasicObject, nil] the current value
93
+ # @yieldreturn [Boolean] whether the value matches
94
+ # @param timeout [Numeric, nil] the total seconds available
95
+ # @return [BasicObject, nil] the matching value, or nil on timeout
96
+ # @raise [LocalJumpError] if no block is given
97
+ def wait_until(timeout: nil, &) = Internal.wait_until(self, timeout:, &)
98
+
99
+ # Wait while the block returns a truthy value.
100
+ # @yieldparam value [BasicObject, nil] the current value
101
+ # @yieldreturn [BasicObject] a truthy value to keep waiting, or nil or false to stop
102
+ # @param timeout [Numeric, nil] the total seconds available
103
+ # @return [BasicObject, nil] the value when the condition becomes false, or nil on timeout
104
+ # @raise [LocalJumpError] if no block is given
105
+ def wait_while(timeout: nil)
106
+ raise LocalJumpError, "no block given" unless block_given?
107
+ wait_until(timeout:) { |value| !yield(value) }
108
+ end
109
+
110
+ # Wait while `object === value` is true.
111
+ # @param object [#===] the pattern to stop matching
112
+ # @param timeout [Numeric, nil] the total seconds available
113
+ # @return [BasicObject, nil] the first nonmatching value, or nil on timeout
114
+ def wait_while_match(object, timeout: nil)
115
+ wait_while(timeout:) { |value| object === value } # rubocop:disable Style/CaseEquality
116
+ end
117
+
118
+ # (see #wait_until_changed)
119
+ def wait_while_value(...) = wait_until_changed(...)
120
+
121
+ # Wait until the current value equals an object using the configured comparison mode.
122
+ # @param object [BasicObject, nil] the value to compare with the current value
123
+ # @param timeout [Numeric, nil] the total seconds available
124
+ # @return [BasicObject, nil] the matching value, or nil on timeout
125
+ def wait_until_value(object, timeout: nil)
126
+ wait_until(timeout:) { |value| compare_by_identity? ? object.equal?(value) : object == value }
127
+ end
128
+
129
+ # Wait until `object === value` is true.
130
+ # @param object [#===] the pattern to match
131
+ # @param timeout [Numeric, nil] the total seconds available
132
+ # @return [BasicObject, nil] the matching value, or nil on timeout
133
+ def wait_until_match(object, timeout: nil)
134
+ wait_until(timeout:) { |value| object === value } # rubocop:disable Style/CaseEquality
135
+ end
136
+
137
+ # Wait until the current value no longer matches an expected value.
138
+ # @param expected [BasicObject, nil] the value to compare with the current value
139
+ # @param timeout [Numeric, nil] the maximum number of seconds to wait
140
+ # @yield called when the timeout expires
141
+ # @return [BasicObject, nil] the changed value or the fallback result
142
+ def wait_until_changed(expected, timeout: nil, &)
143
+ internal_atom.wait_until_changed(expected, timeout:, &)
144
+ end
145
+
146
+ # Wait until the current value is not nil.
147
+ # @param timeout [Numeric, nil] the maximum number of seconds to wait
148
+ # @yield called when the timeout expires
149
+ # @return [BasicObject, nil] the non-nil value or the fallback result
150
+ def wait_until_non_nil(timeout: nil, &) = internal_atom.wait_until_non_nil(timeout:, &)
151
+
152
+ # @api private
153
+ def inspect_with(inspector)
154
+ super do
155
+ yield if block_given?
156
+ inspect_value(inspector)
157
+ end
158
+ end
159
+
160
+ protected
161
+
162
+ def internal_atom = @atom
163
+
164
+ private
165
+
166
+ def inspect_value(inspector, prefix = "value=")
167
+ if prefix
168
+ inspector.breakable
169
+ inspector.text(prefix)
170
+ end
171
+ inspector.object(value)
172
+ end
173
+
174
+ def initialize_copy(other)
175
+ super
176
+ source = other.internal_atom
177
+ copy = source.class.new(source.value, compare_by_identity: source.compare_by_identity?)
178
+ if is_a?(Local::Scoped)
179
+ Internal::Storage.scope(scope)[self] = copy
180
+ else
181
+ @atom = copy
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,232 @@
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 maps that retain at most a configured number of entries.
8
+ #
9
+ # Successful individual value reads and writes update the map's eviction policy.
10
+ # Observational operations such as iteration, {#key?}, and {#getkey} do not.
11
+ # Copies preserve capacity and eviction history without counting copying as an access.
12
+ class BoundedMap < Map
13
+ include DuplicableMap
14
+
15
+ # @param entries [Hash, Array<Array(BasicObject, BasicObject)>, Map, #each, nil]
16
+ # Optional initial entries. Entries are stored sequentially and may be evicted.
17
+ # @param max_size [Integer] Maximum number of retained entries.
18
+ # @!macro key_normalization
19
+ # @param compare_by_identity [Boolean] Whether keys and values are compared by identity.
20
+ # @param compare_keys_by_identity [Boolean] Whether keys are compared by identity.
21
+ # @param compare_values_by_identity [Boolean] Whether values are compared by identity.
22
+ def initialize(
23
+ entries = nil,
24
+ max_size:,
25
+ normalize_keys: nil,
26
+ compare_by_identity: false,
27
+ compare_keys_by_identity: compare_by_identity,
28
+ compare_values_by_identity: compare_by_identity
29
+ )
30
+ entries = convert_entries(entries)
31
+ @map = new_bounded_map(
32
+ max_size:,
33
+ compare_by_identity:,
34
+ compare_keys_by_identity:,
35
+ compare_values_by_identity:,
36
+ )
37
+ @key_locks = new_key_locks(compare_keys_by_identity:)
38
+ restoring = Internal::KeyNormalizer.restoration?(normalize_keys)
39
+ normalizer = Internal::KeyNormalizer.build(
40
+ normalize_keys,
41
+ shareable: normalize_keys && Internal::KeyNormalizer.shareable_target?(self),
42
+ )
43
+ Internal::KeyNormalizer.install(self, normalizer, Internal::KeyNormalizer::BoundedOperations) unless restoring
44
+ entries&.each { self[_1] = _2 }
45
+ Internal::KeyNormalizer.install(self, normalizer, Internal::KeyNormalizer::BoundedOperations) if restoring
46
+ super()
47
+ end
48
+
49
+ # (see Map#[])
50
+ def [](key) = unwrap_value(internal_map[prepare_key(key)])
51
+
52
+ # (see Map#[]=)
53
+ def []=(key, value)
54
+ key = prepare_store_key(key)
55
+ with_key_lock(key) { internal_map[key] = wrap_value(value) }
56
+ value
57
+ end
58
+
59
+ # Return an existing value, or store the block result for an absent key.
60
+ # Coordinated implementations share one initialization among concurrent
61
+ # callers for equal keys. Unsafe implementations can run competing loaders.
62
+ # The block runs without holding the map's structural lock, so other keys
63
+ # remain accessible. Coordinated assignment waits for initialization.
64
+ # Deletion or clearing can precede a pending initialization's insertion.
65
+ # At zero capacity, coordinated implementations run equal-key loaders
66
+ # sequentially. Each loader validates and transfers its result, but the
67
+ # map retains no value.
68
+ # @param key [BasicObject] The key to retrieve or initialize.
69
+ # @yieldreturn [BasicObject] The value to store.
70
+ # @return [BasicObject] The existing or newly stored value.
71
+ # @raise [LocalJumpError] If no block is given, even when the key exists.
72
+ # @raise [ThreadError] If coordinated initialization recursively accesses its own gate.
73
+ def store_if_absent(key)
74
+ raise LocalJumpError, "no block given" unless block_given?
75
+
76
+ map = internal_map
77
+ found = true
78
+ stored = map.fetch(prepare_key(key)) { found = false }
79
+ return unwrap_value(stored) if found
80
+
81
+ key = prepare_store_key(key)
82
+ with_key_lock(key) do
83
+ stored = map.fetch(key) do
84
+ wrapped = wrap_value(yield)
85
+ map[key] = wrapped
86
+ return unwrap_value(wrapped)
87
+ end
88
+ unwrap_value(stored)
89
+ end
90
+ end
91
+
92
+ # (see Map#clear)
93
+ def clear
94
+ internal_map.clear
95
+ self
96
+ end
97
+
98
+ # (see Map#compare_keys_by_identity?)
99
+ def compare_keys_by_identity? = internal_map.compare_keys_by_identity?
100
+
101
+ # (see Map#compare_values_by_identity?)
102
+ def compare_values_by_identity? = internal_map.compare_values_by_identity?
103
+
104
+ # (see Map#delete)
105
+ def delete(key) = unwrap_value(internal_map.delete(prepare_key(key)))
106
+
107
+ # (see Map#fetch)
108
+ def fetch(*arguments)
109
+ unless arguments.length.between?(1, 2)
110
+ raise ArgumentError, "wrong number of arguments (given #{arguments.length}, expected 1..2)"
111
+ end
112
+
113
+ key, default = arguments
114
+ prepared_key = prepare_key(key)
115
+ warn "block supersedes default value argument", uplevel: 1 if block_given? && arguments.length == 2
116
+ value = internal_map.fetch(prepared_key) do
117
+ return yield(key) if block_given?
118
+ return default if arguments.length == 2
119
+ raise KeyError.new("key not found: #{key.inspect}", receiver: self, key: key)
120
+ end
121
+ unwrap_value(value)
122
+ end
123
+
124
+ # (see Map#getkey)
125
+ def getkey(key) = internal_map.getkey(prepare_key(key))
126
+
127
+ # (see Map#key?)
128
+ def key?(key) = internal_map.key?(prepare_key(key))
129
+
130
+ # Return the maximum number of entries retained by the current backing map.
131
+ # @return [Integer]
132
+ def max_size = internal_map.max_size
133
+
134
+ # Change the maximum number of retained entries and immediately evict any excess.
135
+ # @param limit [Integer] The new non-negative capacity.
136
+ # @return [Integer] `limit`
137
+ def max_size=(limit)
138
+ internal_map.max_size = limit
139
+ end
140
+
141
+ # Remove entries selected by the eviction policy until at most `to` remain.
142
+ # This does not change {#max_size}.
143
+ # @param to [Integer] The non-negative target size.
144
+ # @return [Integer] Number of entries removed.
145
+ def prune(to:) = internal_map.prune(to:)
146
+
147
+ # Remove and return the next entry selected by the eviction policy.
148
+ # @return [Array(BasicObject, BasicObject), nil]
149
+ def shift
150
+ pair = internal_map.shift
151
+ [pair.first, unwrap_value(pair.last)] if pair
152
+ end
153
+
154
+ # (see Map#size)
155
+ def size = internal_map.size
156
+ alias length size
157
+
158
+ # Iterate over a snapshot without updating eviction history.
159
+ # @overload each
160
+ # @yield [pair] Called once for each entry.
161
+ # @yieldparam pair [Array<BasicObject>] A two-element `[key, value]` pair.
162
+ # @return [self]
163
+ # @overload each
164
+ # @return [Enumerator]
165
+ def each
166
+ return enum_for(__method__) unless block_given?
167
+ internal_map.each { |key, value| yield [key, unwrap_value(value)] }
168
+ self
169
+ end
170
+ alias each_pair each
171
+
172
+ # Iterate over a snapshot of stored keys without updating eviction history.
173
+ # @return [self, Enumerator]
174
+ def each_key
175
+ return enum_for(__method__) unless block_given?
176
+ internal_map.each_key { yield it }
177
+ self
178
+ end
179
+
180
+ # Iterate over a snapshot of stored values without updating eviction history.
181
+ # @return [self, Enumerator]
182
+ def each_value
183
+ return enum_for(__method__) unless block_given?
184
+ internal_map.each_value { yield unwrap_value(it) }
185
+ self
186
+ end
187
+
188
+ # Return a frozen snapshot of stored keys.
189
+ # @return [Array<BasicObject>]
190
+ def keys = each_key.to_a.freeze
191
+
192
+ # Return a frozen snapshot of stored values.
193
+ # @return [Array<BasicObject>]
194
+ def values = each_value.to_a.freeze
195
+
196
+ private
197
+
198
+ def copy_map_backend(source, empty: false)
199
+ return source.dup unless empty
200
+ source.class.new(
201
+ max_size: source.max_size,
202
+ compare_keys_by_identity: source.compare_keys_by_identity?,
203
+ compare_values_by_identity: source.compare_values_by_identity?,
204
+ )
205
+ end
206
+
207
+ def install_copied_map(map)
208
+ super
209
+ @key_locks = new_key_locks(compare_keys_by_identity: map.compare_keys_by_identity?)
210
+ end
211
+
212
+ def each_for_inspect(&) = each(&)
213
+ def prepare_key(key) = key
214
+ def prepare_store_key(key) = internal_map.prepare_key(prepare_key(key))
215
+ def with_key_lock(key, &) = @key_locks.synchronize(key, &)
216
+
217
+ # simplecov:disable
218
+ def new_key_locks(...)
219
+ raise "subclass failed to implement #new_key_locks" unless instance_of?(BoundedMap)
220
+ raise NoMethodError, "Farce::Abstract::BoundedMap should not be instantiated directly. Use a subclass instead."
221
+ end
222
+ # simplecov:enable
223
+
224
+ # simplecov:disable
225
+ def new_bounded_map(...)
226
+ raise "subclass failed to implement #new_bounded_map" unless instance_of?(BoundedMap)
227
+ raise NoMethodError, "Farce::Abstract::BoundedMap should not be instantiated directly. Use a subclass instead."
228
+ end
229
+ # simplecov:enable
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,151 @@
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 a collection of elements.
8
+ #
9
+ # Subclasses define traversal, comparison, and insertion rules.
10
+ # They may accept additional optional parameters for the methods below.
11
+ #
12
+ # Notable subclasses include {Vector}, {Set}, and {SortedSet}.
13
+ #
14
+ # @!method each
15
+ # Iterate over the elements currently present.
16
+ # @yield [element] Visit each element. Returns an Enumerator without a block.
17
+ # @yieldparam element [BasicObject] The current element.
18
+ # @yieldreturn [void] The result is ignored.
19
+ # @return [self, Enumerator] Self, or a sized Enumerator without a block.
20
+ # @abstract
21
+ #
22
+ # @!method size
23
+ # Return the number of elements currently present.
24
+ # @return [Integer] The number of elements.
25
+ # @abstract
26
+ #
27
+ # @!method to_a
28
+ # Return the observed elements in a new Array.
29
+ # @return [Array<BasicObject>] The observed elements.
30
+ # @abstract
31
+ #
32
+ # @!method clear
33
+ # Remove all elements and return self.
34
+ # @return [self] The collection.
35
+ # @abstract
36
+ #
37
+ # @!method include?(element)
38
+ # Return whether an element is present using the collection's membership rules.
39
+ # @param element [BasicObject] The element to look up.
40
+ # @return [Boolean] Whether the element is present.
41
+ # @abstract
42
+ #
43
+ # @!method member?(element)
44
+ # Return whether an element is present, as with {#include?}.
45
+ # @param element [BasicObject] The element to look up.
46
+ # @return [Boolean] Whether the element is present.
47
+ # @see #include?
48
+ # @abstract
49
+ #
50
+ # @!method compare_by_identity?
51
+ # Return whether elements are compared by object identity.
52
+ # @return [Boolean] Whether identity comparison is enabled.
53
+ # @abstract
54
+ #
55
+ # @!method select
56
+ # Return a collection of the same kind containing elements accepted by the block.
57
+ # @yield [element] Test each element. Returns an Enumerator without a block.
58
+ # @yieldparam element [BasicObject] The current element.
59
+ # @yieldreturn [BasicObject] A truthy value to retain the element.
60
+ # @return [Farce::Abstract::Collection, Enumerator] A new collection, or an Enumerator without a block.
61
+ # @abstract
62
+ #
63
+ # @!method filter
64
+ # Return elements accepted by the block, as with {#select}.
65
+ # @yield [element] Test each element. Returns an Enumerator without a block.
66
+ # @yieldparam element [BasicObject] The current element.
67
+ # @yieldreturn [BasicObject] A truthy value to retain the element.
68
+ # @return [Farce::Abstract::Collection, Enumerator] A new collection of the same kind, or an Enumerator.
69
+ # @see #select
70
+ # @abstract
71
+ #
72
+ # @!method reject
73
+ # Return a collection of the same kind excluding elements accepted by the block.
74
+ # @yield [element] Test each element. Returns an Enumerator without a block.
75
+ # @yieldparam element [BasicObject] The current element.
76
+ # @yieldreturn [BasicObject] A truthy value to exclude the element.
77
+ # @return [Farce::Abstract::Collection, Enumerator] A new collection, or an Enumerator without a block.
78
+ # @abstract
79
+ #
80
+ # @!method <<(element)
81
+ # Add an element using the collection's insertion rules and return self.
82
+ # @param element [BasicObject] The element to add.
83
+ # @return [self] The collection.
84
+ # @abstract
85
+ class Collection
86
+ include Enumerable
87
+ include Internal::Copyable
88
+ include Internal::Inspect
89
+
90
+ # @overload [](*elements, **options)
91
+ # Construct a collection from the arguments.
92
+ # @param elements [Array<BasicObject>] The initial elements.
93
+ # @param **options [Hash] Additional options passed to the constructor.
94
+ # @return [Farce::Abstract::Collection] A new instance of the receiving class.
95
+ def self.[](*elements, **) = new(elements, **)
96
+
97
+ # Return the number of elements currently present.
98
+ # @return [Integer] The collection's size.
99
+ def length = size
100
+
101
+ # Return whether no elements are present.
102
+ # @return [Boolean] Whether the collection is empty.
103
+ def empty? = size.zero?
104
+
105
+ # Count all elements, matching elements, or elements accepted by a block.
106
+ # Without an argument or block, read the size without traversing elements.
107
+ # @param item [BasicObject] The value to count. Omit to count all elements or use the block.
108
+ # @yield [element] Select elements to count when item is omitted.
109
+ # @yieldparam element [BasicObject] The current element.
110
+ # @yieldreturn [BasicObject] A truthy value to count the element.
111
+ # @return [Integer] The number of matching elements.
112
+ def count(item = UNDEFINED)
113
+ return size if item.equal?(UNDEFINED) && !block_given?
114
+
115
+ if item.equal?(UNDEFINED)
116
+ super() { yield it }
117
+ else
118
+ warn("given block not used") if block_given?
119
+ super(item, &nil)
120
+ end
121
+ end
122
+
123
+ # Join the elements through Array#join.
124
+ # @param separator [String, nil] The separator. Nil uses Array's default separator.
125
+ # @return [String] The joined elements.
126
+ def join(separator = nil) = to_a.join(separator)
127
+
128
+ # @return [String] The class name and observed elements, suitable for debugging.
129
+ def to_s = inspect
130
+
131
+ # @api private
132
+ def inspect_with(inspector)
133
+ super do
134
+ yield if block_given?
135
+ inspector.breakable
136
+ inspector.group("[", "]") do
137
+ inspector.breakable ""
138
+ inspector.seplist(self, nil, :each_for_inspect) do |value|
139
+ inspector.group { inspect_value(inspector, value) }
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ private
146
+
147
+ def each_for_inspect(&) = each(&)
148
+ def inspect_value(inspector, ...) = inspector.object(...)
149
+ end
150
+ end
151
+ end