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,1195 @@
1
+ #include "containers.h"
2
+ #include "transaction.h"
3
+ #include "ruby/io.h"
4
+ #include "ruby/fiber/scheduler.h"
5
+
6
+ #include <errno.h>
7
+ #include <fcntl.h>
8
+ #include <math.h>
9
+ #include <stdint.h>
10
+ #include <stdlib.h>
11
+ #include <time.h>
12
+ #include <unistd.h>
13
+
14
+ #define VECTOR_INITIAL_CAPACITY 16
15
+ static VALUE cVector;
16
+ static ID vector_values_id, vector_updating_id, vector_mutex_id;
17
+ static VALUE vector_transaction_marker;
18
+
19
+ typedef struct vector_waiter vector_waiter_t;
20
+
21
+ struct vector_waiter {
22
+ int read_fd;
23
+ int write_fd;
24
+ bool notified;
25
+ vector_waiter_t *next;
26
+ };
27
+
28
+ typedef struct {
29
+ pthread_mutex_t lock;
30
+ VALUE *values;
31
+ size_t capacity;
32
+ size_t size;
33
+ vector_waiter_t *waiters;
34
+ uint64_t generation;
35
+ bool compare_by_identity;
36
+ uint8_t updating;
37
+ bool initialized;
38
+ VALUE updating_fiber;
39
+ VALUE updating_thread;
40
+ } vector_t;
41
+
42
+ typedef struct {
43
+ bool finite;
44
+ double deadline;
45
+ } vector_timeout_t;
46
+
47
+ static void
48
+ vector_mark(void *pointer)
49
+ {
50
+ vector_t *vector = pointer;
51
+ rb_gc_mark_movable(vector->updating_fiber);
52
+ rb_gc_mark_movable(vector->updating_thread);
53
+ if (!vector->values) return;
54
+ for (size_t index = 0; index < vector->size; index++) {
55
+ rb_gc_mark_movable(vector->values[index]);
56
+ }
57
+ }
58
+
59
+ static void
60
+ vector_compact(void *pointer)
61
+ {
62
+ vector_t *vector = pointer;
63
+ vector->updating_fiber = rb_gc_location(vector->updating_fiber);
64
+ vector->updating_thread = rb_gc_location(vector->updating_thread);
65
+ if (!vector->values) return;
66
+ for (size_t index = 0; index < vector->size; index++) {
67
+ vector->values[index] = rb_gc_location(vector->values[index]);
68
+ }
69
+ }
70
+
71
+ static void
72
+ vector_free(void *pointer)
73
+ {
74
+ vector_t *vector = pointer;
75
+ pthread_mutex_destroy(&vector->lock);
76
+ free(vector->values);
77
+ ruby_xfree(vector);
78
+ }
79
+
80
+ static size_t
81
+ vector_memsize(const void *pointer)
82
+ {
83
+ const vector_t *vector = pointer;
84
+ return vector ? sizeof(vector_t) + vector->capacity * sizeof(VALUE) : 0;
85
+ }
86
+
87
+ static const rb_data_type_t vector_type = {
88
+ .wrap_struct_name = "Ractor::Containers::Vector",
89
+ .function = {
90
+ .dmark = vector_mark,
91
+ .dfree = vector_free,
92
+ .dsize = vector_memsize,
93
+ .dcompact = vector_compact,
94
+ },
95
+ .flags = RUBY_TYPED_FROZEN_SHAREABLE,
96
+ };
97
+
98
+ static void
99
+ vector_validate_references(VALUE self)
100
+ {
101
+ vector_t *vector;
102
+ TypedData_Get_Struct(self, vector_t, &vector_type, vector);
103
+ for (size_t index = 0; index < vector->size; index++) {
104
+ containers_check_shareable(vector->values[index]);
105
+ }
106
+ }
107
+
108
+ static VALUE
109
+ vector_allocate(VALUE klass)
110
+ {
111
+ vector_t *vector;
112
+ VALUE object = TypedData_Make_Struct(klass, vector_t, &vector_type, vector);
113
+ pthread_mutex_init(&vector->lock, NULL);
114
+ vector->values = NULL;
115
+ vector->capacity = 0;
116
+ vector->size = 0;
117
+ vector->waiters = NULL;
118
+ vector->generation = 0;
119
+ vector->compare_by_identity = false;
120
+ vector->updating = false;
121
+ vector->initialized = false;
122
+ vector->updating_fiber = Qnil;
123
+ vector->updating_thread = Qnil;
124
+ return object;
125
+ }
126
+
127
+ static vector_t *
128
+ get_vector(VALUE self)
129
+ {
130
+ vector_t *vector;
131
+ TypedData_Get_Struct(self, vector_t, &vector_type, vector);
132
+ if (!vector->initialized) rb_raise(rb_eRuntimeError, "uninitialized Vector");
133
+ return vector;
134
+ }
135
+
136
+ static VALUE *
137
+ vector_allocate_values(size_t capacity)
138
+ {
139
+ if (capacity > SIZE_MAX / sizeof(VALUE)) return NULL;
140
+ VALUE *values = malloc(capacity * sizeof(VALUE));
141
+ if (!values) return NULL;
142
+ for (size_t index = 0; index < capacity; index++) values[index] = Qnil;
143
+ return values;
144
+ }
145
+
146
+ static bool
147
+ vector_ensure_capacity(vector_t *vector, size_t required)
148
+ {
149
+ if (required <= vector->capacity) return true;
150
+
151
+ size_t capacity = vector->capacity ? vector->capacity : VECTOR_INITIAL_CAPACITY;
152
+ while (capacity < required) {
153
+ if (capacity > SIZE_MAX / 2) {
154
+ capacity = required;
155
+ break;
156
+ }
157
+ capacity *= 2;
158
+ }
159
+
160
+ VALUE *values = vector_allocate_values(capacity);
161
+ if (!values) return false;
162
+ for (size_t index = 0; index < vector->size; index++) values[index] = vector->values[index];
163
+ free(vector->values);
164
+ vector->values = values;
165
+ vector->capacity = capacity;
166
+ return true;
167
+ }
168
+
169
+ static double
170
+ vector_monotonic_now(void)
171
+ {
172
+ struct timespec now;
173
+ #ifdef CLOCK_MONOTONIC
174
+ if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) {
175
+ return (double)now.tv_sec + (double)now.tv_nsec / 1000000000.0;
176
+ }
177
+ #endif
178
+ struct timeval fallback;
179
+ gettimeofday(&fallback, NULL);
180
+ return (double)fallback.tv_sec + (double)fallback.tv_usec / 1000000.0;
181
+ }
182
+
183
+ static vector_timeout_t
184
+ vector_parse_timeout(VALUE value)
185
+ {
186
+ vector_timeout_t timeout = {.finite = false, .deadline = 0};
187
+ if (NIL_P(value)) return timeout;
188
+
189
+ double seconds = NUM2DBL(value);
190
+ if (!isfinite(seconds) || seconds < 0) {
191
+ rb_raise(rb_eArgError, "timeout must be a finite, non-negative number or nil");
192
+ }
193
+ timeout.finite = true;
194
+ timeout.deadline = vector_monotonic_now() + seconds;
195
+ return timeout;
196
+ }
197
+
198
+ static VALUE
199
+ vector_timeout_keyword(VALUE keywords)
200
+ {
201
+ VALUE timeout = Qnil;
202
+ if (!NIL_P(keywords)) {
203
+ ID keyword_ids[] = {rb_intern("timeout")};
204
+ VALUE keyword_values[1];
205
+ rb_get_kwargs(keywords, keyword_ids, 0, 1, keyword_values);
206
+ if (keyword_values[0] != Qundef) timeout = keyword_values[0];
207
+ }
208
+ return timeout;
209
+ }
210
+
211
+ static void
212
+ vector_set_fd_flags(int fd)
213
+ {
214
+ #ifdef _WIN32
215
+ (void)fd;
216
+ #else
217
+ int flags = fcntl(fd, F_GETFL, 0);
218
+ if (flags >= 0) (void)fcntl(fd, F_SETFL, flags | O_NONBLOCK);
219
+ flags = fcntl(fd, F_GETFD, 0);
220
+ if (flags >= 0) (void)fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
221
+ #endif
222
+ }
223
+
224
+ /* Called with vector->lock held. Each waiter has an independent pipe, so a
225
+ * transition wakes every waiting thread or scheduled fiber. */
226
+ static void
227
+ vector_notify_waiters_locked(vector_t *vector)
228
+ {
229
+ unsigned char byte = 1;
230
+ vector->generation++;
231
+ for (vector_waiter_t *waiter = vector->waiters; waiter; waiter = waiter->next) {
232
+ if (waiter->notified) continue;
233
+ ssize_t result;
234
+ do {
235
+ result = write(waiter->write_fd, &byte, 1);
236
+ } while (result < 0 && errno == EINTR);
237
+ if (result == 1 || (result < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))) {
238
+ waiter->notified = true;
239
+ }
240
+ }
241
+ }
242
+
243
+ static void
244
+ vector_finish_update_locked(vector_t *vector)
245
+ {
246
+ vector->updating = false;
247
+ vector_notify_waiters_locked(vector);
248
+ }
249
+
250
+ typedef struct {
251
+ vector_t *vector;
252
+ vector_waiter_t waiter;
253
+ vector_timeout_t *timeout;
254
+ } vector_wait_context_t;
255
+
256
+ static bool
257
+ vector_wait_for_descriptor(int fd, vector_timeout_t *timeout)
258
+ {
259
+ VALUE wait_timeout = Qnil;
260
+ if (timeout->finite) {
261
+ double remaining = timeout->deadline - vector_monotonic_now();
262
+ if (remaining <= 0) return false;
263
+ wait_timeout = DBL2NUM(remaining);
264
+ }
265
+ return containers_wait_for_readable(fd, wait_timeout);
266
+ }
267
+
268
+ static VALUE
269
+ vector_wait_body(VALUE opaque)
270
+ {
271
+ vector_wait_context_t *context = (vector_wait_context_t *)opaque;
272
+ return vector_wait_for_descriptor(context->waiter.read_fd, context->timeout) ? Qtrue : Qfalse;
273
+ }
274
+
275
+ static VALUE
276
+ vector_wait_cleanup(VALUE opaque)
277
+ {
278
+ vector_wait_context_t *context = (vector_wait_context_t *)opaque;
279
+ vector_waiter_t **link;
280
+
281
+ pthread_mutex_lock(&context->vector->lock);
282
+ for (link = &context->vector->waiters; *link; link = &(*link)->next) {
283
+ if (*link == &context->waiter) {
284
+ *link = context->waiter.next;
285
+ break;
286
+ }
287
+ }
288
+ pthread_mutex_unlock(&context->vector->lock);
289
+ close(context->waiter.read_fd);
290
+ close(context->waiter.write_fd);
291
+ return Qnil;
292
+ }
293
+
294
+ /* Called with vector->lock held and always returns with it released. The
295
+ * waiter is registered before unlocking, which closes the check-to-wait race
296
+ * without requiring a permanent descriptor on every Vector. */
297
+ static bool
298
+ vector_wait_once(vector_t *vector, vector_timeout_t *timeout)
299
+ {
300
+ int descriptors[2];
301
+ if (pipe(descriptors) != 0) {
302
+ pthread_mutex_unlock(&vector->lock);
303
+ rb_sys_fail("pipe");
304
+ }
305
+ vector_set_fd_flags(descriptors[0]);
306
+ vector_set_fd_flags(descriptors[1]);
307
+
308
+ vector_wait_context_t context = {
309
+ .vector = vector,
310
+ .waiter = {
311
+ .read_fd = descriptors[0],
312
+ .write_fd = descriptors[1],
313
+ .notified = false,
314
+ .next = vector->waiters,
315
+ },
316
+ .timeout = timeout,
317
+ };
318
+ vector->waiters = &context.waiter;
319
+ pthread_mutex_unlock(&vector->lock);
320
+ return RTEST(rb_ensure(vector_wait_body, (VALUE)&context, vector_wait_cleanup, (VALUE)&context));
321
+ }
322
+
323
+ static void
324
+ vector_check_reservation_wait_locked(vector_t *vector)
325
+ {
326
+ if (vector->updating != FARCE_TRANSACTION_RESERVED) return;
327
+ pthread_mutex_unlock(&vector->lock);
328
+ VALUE fiber = rb_fiber_current();
329
+ VALUE thread = rb_thread_current();
330
+ VALUE scheduler = rb_fiber_scheduler_current();
331
+ pthread_mutex_lock(&vector->lock);
332
+ if (vector->updating != FARCE_TRANSACTION_RESERVED) return;
333
+ if (vector->updating_fiber == fiber ||
334
+ (vector->updating_thread == thread && NIL_P(scheduler))) {
335
+ pthread_mutex_unlock(&vector->lock);
336
+ rb_raise(rb_eThreadError, "deadlock; recursive or unscheduled vector transaction access");
337
+ }
338
+ }
339
+
340
+ /* Called with the short mutex held. Return with it held on success. */
341
+ static bool
342
+ vector_wait_for_reservation_locked(vector_t *vector, vector_timeout_t *timeout)
343
+ {
344
+ while (vector->updating == FARCE_TRANSACTION_RESERVED) {
345
+ vector_check_reservation_wait_locked(vector);
346
+ if (vector->updating != FARCE_TRANSACTION_RESERVED) break;
347
+ if (!vector_wait_once(vector, timeout) && timeout->finite) return false;
348
+ pthread_mutex_lock(&vector->lock);
349
+ }
350
+ return true;
351
+ }
352
+
353
+ static void
354
+ vector_read_lock(vector_t *vector)
355
+ {
356
+ vector_timeout_t timeout = {.finite = false, .deadline = 0};
357
+ pthread_mutex_lock(&vector->lock);
358
+ (void)vector_wait_for_reservation_locked(vector, &timeout);
359
+ }
360
+
361
+ static VALUE
362
+ vector_freeze(VALUE self)
363
+ {
364
+ vector_t *vector;
365
+ TypedData_Get_Struct(self, vector_t, &vector_type, vector);
366
+ vector_read_lock(vector);
367
+ rb_obj_freeze(self);
368
+ pthread_mutex_unlock(&vector->lock);
369
+ return self;
370
+ }
371
+
372
+ /* Returns with vector->lock held on success and released on timeout. */
373
+ static bool
374
+ vector_lock_for_update(vector_t *vector, vector_timeout_t *timeout)
375
+ {
376
+ for (;;) {
377
+ pthread_mutex_lock(&vector->lock);
378
+ if (!vector->updating) return true;
379
+ vector_check_reservation_wait_locked(vector);
380
+ if (!vector->updating) return true;
381
+ if (!vector_wait_once(vector, timeout)) return false;
382
+ }
383
+ }
384
+
385
+ static long long
386
+ vector_convert_index(VALUE value)
387
+ {
388
+ return NUM2LL(value);
389
+ }
390
+
391
+ static bool
392
+ vector_lookup_index(vector_t *vector, long long raw, size_t *index)
393
+ {
394
+ if (raw < 0) {
395
+ unsigned long long distance = (unsigned long long)(-(raw + 1)) + 1;
396
+ if (distance > vector->size) return false;
397
+ *index = vector->size - (size_t)distance;
398
+ return true;
399
+ }
400
+ if ((unsigned long long)raw >= vector->size) return false;
401
+ *index = (size_t)raw;
402
+ return true;
403
+ }
404
+
405
+ /* Called with the lock held. Raises only after releasing it. */
406
+ static size_t
407
+ vector_assignment_index(vector_t *vector, long long raw)
408
+ {
409
+ if (raw < 0) {
410
+ unsigned long long distance = (unsigned long long)(-(raw + 1)) + 1;
411
+ if (distance > vector->size) {
412
+ pthread_mutex_unlock(&vector->lock);
413
+ rb_raise(rb_eIndexError, "index %lld too small for vector; minimum: -%zu", raw, vector->size);
414
+ }
415
+ return vector->size - (size_t)distance;
416
+ }
417
+ if ((unsigned long long)raw >= SIZE_MAX) {
418
+ pthread_mutex_unlock(&vector->lock);
419
+ rb_raise(rb_eIndexError, "index %lld too large", raw);
420
+ }
421
+ return (size_t)raw;
422
+ }
423
+
424
+ static VALUE
425
+ vector_initialize(int argc, VALUE *argv, VALUE self)
426
+ {
427
+ VALUE source = Qnil;
428
+ VALUE keywords = Qnil;
429
+ VALUE identity = Qundef;
430
+ ID keyword_ids[] = {rb_intern("compare_by_identity")};
431
+ VALUE keyword_values[1];
432
+ vector_t *vector;
433
+
434
+ rb_check_frozen(self);
435
+ rb_scan_args(argc, argv, "01:", &source, &keywords);
436
+ if (!NIL_P(keywords)) {
437
+ rb_get_kwargs(keywords, keyword_ids, 0, 1, keyword_values);
438
+ identity = keyword_values[0];
439
+ }
440
+ TypedData_Get_Struct(self, vector_t, &vector_type, vector);
441
+ if (vector->initialized) rb_raise(rb_eRuntimeError, "Vector is already initialized");
442
+
443
+ vector->compare_by_identity = identity == Qundef
444
+ ? false
445
+ : containers_strict_bool(identity, "compare_by_identity");
446
+
447
+ size_t size = 0;
448
+ if (!NIL_P(source)) {
449
+ Check_Type(source, T_ARRAY);
450
+ size = (size_t)RARRAY_LEN(source);
451
+ }
452
+ size_t capacity = size > VECTOR_INITIAL_CAPACITY ? size : VECTOR_INITIAL_CAPACITY;
453
+ vector->values = vector_allocate_values(capacity);
454
+ if (!vector->values) rb_memerror();
455
+ vector->capacity = capacity;
456
+
457
+ for (size_t index = 0; index < size; index++) {
458
+ VALUE value = RARRAY_AREF(source, (long)index);
459
+ containers_check_shareable(value);
460
+ vector->values[index] = value;
461
+ }
462
+ vector->size = size;
463
+ vector->initialized = true;
464
+ return containers_publish_native_with_references(self, vector_validate_references);
465
+ }
466
+
467
+ static VALUE
468
+ vector_snapshot_locked(VALUE self)
469
+ {
470
+ vector_t *vector = get_vector(self);
471
+ return rb_ary_new_from_values((long)vector->size, vector->values);
472
+ }
473
+
474
+ static VALUE
475
+ vector_snapshot_unlock(VALUE self)
476
+ {
477
+ pthread_mutex_unlock(&get_vector(self)->lock);
478
+ return Qnil;
479
+ }
480
+
481
+ static VALUE
482
+ vector_snapshot(VALUE self)
483
+ {
484
+ vector_read_lock(get_vector(self));
485
+ return rb_ensure(vector_snapshot_locked, self, vector_snapshot_unlock, self);
486
+ }
487
+
488
+ static VALUE
489
+ vector_size(VALUE self)
490
+ {
491
+ vector_t *vector = get_vector(self);
492
+ size_t size;
493
+ vector_read_lock(vector);
494
+ size = vector->size;
495
+ pthread_mutex_unlock(&vector->lock);
496
+ return SIZET2NUM(size);
497
+ }
498
+
499
+ /* Never retain a backing-buffer pointer or hold the lock across a Ruby yield. */
500
+ static VALUE
501
+ vector_each(VALUE self)
502
+ {
503
+ RETURN_ENUMERATOR(self, 0, NULL);
504
+ vector_t *vector = get_vector(self);
505
+ vector_read_lock(vector);
506
+ size_t limit = vector->size;
507
+ pthread_mutex_unlock(&vector->lock);
508
+
509
+ for (size_t index = 0; index < limit; index++) {
510
+ vector_read_lock(vector);
511
+ if (index >= vector->size) {
512
+ pthread_mutex_unlock(&vector->lock);
513
+ break;
514
+ }
515
+ VALUE value = vector->values[index];
516
+ pthread_mutex_unlock(&vector->lock);
517
+ rb_yield(value);
518
+ }
519
+ return self;
520
+ }
521
+
522
+ static VALUE
523
+ vector_reverse_each(VALUE self)
524
+ {
525
+ RETURN_ENUMERATOR(self, 0, NULL);
526
+ vector_t *vector = get_vector(self);
527
+ vector_read_lock(vector);
528
+ size_t index = vector->size;
529
+ pthread_mutex_unlock(&vector->lock);
530
+
531
+ while (index > 0) {
532
+ vector_read_lock(vector);
533
+ if (index > vector->size) index = vector->size;
534
+ if (index == 0) {
535
+ pthread_mutex_unlock(&vector->lock);
536
+ break;
537
+ }
538
+ VALUE value = vector->values[--index];
539
+ pthread_mutex_unlock(&vector->lock);
540
+ rb_yield(value);
541
+ }
542
+ return self;
543
+ }
544
+
545
+ static VALUE
546
+ vector_fetch(VALUE self, VALUE index_value)
547
+ {
548
+ vector_t *vector = get_vector(self);
549
+ long long raw = vector_convert_index(index_value);
550
+ size_t index;
551
+ vector_read_lock(vector);
552
+ bool found = vector_lookup_index(vector, raw, &index);
553
+ VALUE result = found ? vector->values[index] : Qnil;
554
+ pthread_mutex_unlock(&vector->lock);
555
+ if (found) return result;
556
+ if (rb_block_given_p()) return rb_yield(index_value);
557
+ rb_raise(rb_eIndexError, "index %lld outside of vector bounds", raw);
558
+ }
559
+
560
+ static VALUE
561
+ vector_compare_by_identity_p(VALUE self)
562
+ {
563
+ return get_vector(self)->compare_by_identity ? Qtrue : Qfalse;
564
+ }
565
+
566
+ static VALUE
567
+ vector_get_fast(VALUE self, VALUE index_value)
568
+ {
569
+ vector_t *vector = get_vector(self);
570
+ long long raw = vector_convert_index(index_value);
571
+ size_t index;
572
+ VALUE result = Qnil;
573
+ vector_read_lock(vector);
574
+ if (vector_lookup_index(vector, raw, &index)) result = vector->values[index];
575
+ pthread_mutex_unlock(&vector->lock);
576
+ return result;
577
+ }
578
+
579
+ static VALUE
580
+ vector_get(int argc, VALUE *argv, VALUE self)
581
+ {
582
+ VALUE index_value;
583
+ VALUE keywords = Qnil;
584
+ rb_scan_args(argc, argv, "1:", &index_value, &keywords);
585
+ long long raw = vector_convert_index(index_value);
586
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
587
+ vector_t *vector = get_vector(self);
588
+
589
+ if (!vector_lock_for_update(vector, &timeout)) return Qnil;
590
+ size_t index;
591
+ VALUE result = vector_lookup_index(vector, raw, &index) ? vector->values[index] : Qnil;
592
+ pthread_mutex_unlock(&vector->lock);
593
+ return result;
594
+ }
595
+
596
+ static VALUE
597
+ vector_store_internal(VALUE self, vector_t *vector, long long raw, VALUE value, vector_timeout_t *timeout)
598
+ {
599
+ rb_check_frozen(self);
600
+ if (!vector_lock_for_update(vector, timeout)) return Qfalse;
601
+ size_t index = vector_assignment_index(vector, raw);
602
+ if (!vector_ensure_capacity(vector, index + 1)) {
603
+ pthread_mutex_unlock(&vector->lock);
604
+ rb_memerror();
605
+ }
606
+ if (index >= vector->size) vector->size = index + 1;
607
+ vector->values[index] = value;
608
+ vector_notify_waiters_locked(vector);
609
+ pthread_mutex_unlock(&vector->lock);
610
+ return value;
611
+ }
612
+
613
+ static VALUE
614
+ vector_set_fast(VALUE self, VALUE index_value, VALUE value)
615
+ {
616
+ vector_t *vector = get_vector(self);
617
+ rb_check_frozen(self);
618
+ long long raw = vector_convert_index(index_value);
619
+ rb_check_frozen(self);
620
+ vector_timeout_t timeout = {.finite = false, .deadline = 0};
621
+ containers_check_shareable(value);
622
+ return vector_store_internal(self, vector, raw, value, &timeout);
623
+ }
624
+
625
+ static VALUE
626
+ vector_store(int argc, VALUE *argv, VALUE self)
627
+ {
628
+ VALUE index_value;
629
+ VALUE value;
630
+ VALUE keywords = Qnil;
631
+ rb_scan_args(argc, argv, "2:", &index_value, &value, &keywords);
632
+ rb_check_frozen(self);
633
+ long long raw = vector_convert_index(index_value);
634
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
635
+ rb_check_frozen(self);
636
+ vector_t *vector = get_vector(self);
637
+ containers_check_shareable(value);
638
+ return vector_store_internal(self, vector, raw, value, &timeout);
639
+ }
640
+
641
+ static VALUE
642
+ vector_clear(VALUE self)
643
+ {
644
+ vector_t *vector = get_vector(self);
645
+ rb_check_frozen(self);
646
+ vector_timeout_t timeout = {.finite = false, .deadline = 0};
647
+ (void)vector_lock_for_update(vector, &timeout);
648
+ for (size_t index = 0; index < vector->size; index++) vector->values[index] = Qnil;
649
+ vector->size = 0;
650
+ vector_notify_waiters_locked(vector);
651
+ pthread_mutex_unlock(&vector->lock);
652
+ return self;
653
+ }
654
+
655
+ static VALUE
656
+ vector_push(int argc, VALUE *argv, VALUE self)
657
+ {
658
+ VALUE value;
659
+ VALUE keywords = Qnil;
660
+ rb_scan_args(argc, argv, "1:", &value, &keywords);
661
+ rb_check_frozen(self);
662
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
663
+ rb_check_frozen(self);
664
+ vector_t *vector = get_vector(self);
665
+ containers_check_shareable(value);
666
+
667
+ if (!vector_lock_for_update(vector, &timeout)) return Qfalse;
668
+ if (vector->size == SIZE_MAX || !vector_ensure_capacity(vector, vector->size + 1)) {
669
+ pthread_mutex_unlock(&vector->lock);
670
+ rb_memerror();
671
+ }
672
+ vector->values[vector->size++] = value;
673
+ vector_notify_waiters_locked(vector);
674
+ pthread_mutex_unlock(&vector->lock);
675
+ return self;
676
+ }
677
+
678
+ static VALUE
679
+ vector_pop(int argc, VALUE *argv, VALUE self)
680
+ {
681
+ VALUE keywords = Qnil;
682
+ rb_scan_args(argc, argv, "0:", &keywords);
683
+ rb_check_frozen(self);
684
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
685
+ rb_check_frozen(self);
686
+ vector_t *vector = get_vector(self);
687
+
688
+ if (!vector_lock_for_update(vector, &timeout)) return Qnil;
689
+ VALUE result = Qnil;
690
+ if (vector->size > 0) {
691
+ size_t index = --vector->size;
692
+ result = vector->values[index];
693
+ vector->values[index] = Qnil;
694
+ vector_notify_waiters_locked(vector);
695
+ }
696
+ pthread_mutex_unlock(&vector->lock);
697
+ return result;
698
+ }
699
+
700
+ static VALUE
701
+ vector_swap(int argc, VALUE *argv, VALUE self)
702
+ {
703
+ VALUE index_value;
704
+ VALUE replacement;
705
+ VALUE keywords = Qnil;
706
+ rb_scan_args(argc, argv, "2:", &index_value, &replacement, &keywords);
707
+ rb_check_frozen(self);
708
+ long long raw = vector_convert_index(index_value);
709
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
710
+ rb_check_frozen(self);
711
+ vector_t *vector = get_vector(self);
712
+ containers_check_shareable(replacement);
713
+
714
+ if (!vector_lock_for_update(vector, &timeout)) return Qnil;
715
+ size_t index = vector_assignment_index(vector, raw);
716
+ if (!vector_ensure_capacity(vector, index + 1)) {
717
+ pthread_mutex_unlock(&vector->lock);
718
+ rb_memerror();
719
+ }
720
+ VALUE previous = index < vector->size ? vector->values[index] : Qnil;
721
+ if (index >= vector->size) vector->size = index + 1;
722
+ vector->values[index] = replacement;
723
+ vector_notify_waiters_locked(vector);
724
+ pthread_mutex_unlock(&vector->lock);
725
+ return previous;
726
+ }
727
+
728
+ typedef struct {
729
+ VALUE self;
730
+ vector_t *vector;
731
+ size_t index;
732
+ VALUE current;
733
+ VALUE argument;
734
+ VALUE replacement;
735
+ bool identity;
736
+ bool complete;
737
+ } vector_operation_t;
738
+
739
+ static VALUE
740
+ vector_operation_cleanup(VALUE opaque)
741
+ {
742
+ vector_operation_t *operation = (vector_operation_t *)opaque;
743
+ if (!operation->complete) {
744
+ pthread_mutex_lock(&operation->vector->lock);
745
+ vector_finish_update_locked(operation->vector);
746
+ pthread_mutex_unlock(&operation->vector->lock);
747
+ }
748
+ return Qnil;
749
+ }
750
+
751
+ static VALUE
752
+ vector_store_if_absent_body(VALUE opaque)
753
+ {
754
+ vector_operation_t *operation = (vector_operation_t *)opaque;
755
+ VALUE result = rb_yield_values(0);
756
+ rb_check_frozen(operation->self);
757
+ containers_check_shareable(result);
758
+ pthread_mutex_lock(&operation->vector->lock);
759
+ if (operation->index >= operation->vector->size) {
760
+ operation->vector->size = operation->index + 1;
761
+ }
762
+ operation->vector->values[operation->index] = result;
763
+ vector_finish_update_locked(operation->vector);
764
+ pthread_mutex_unlock(&operation->vector->lock);
765
+ operation->complete = true;
766
+ return result;
767
+ }
768
+
769
+ static VALUE
770
+ vector_store_if_absent(int argc, VALUE *argv, VALUE self)
771
+ {
772
+ VALUE index_value;
773
+ VALUE keywords = Qnil;
774
+ rb_scan_args(argc, argv, "1:", &index_value, &keywords);
775
+ rb_check_frozen(self);
776
+ long long raw = vector_convert_index(index_value);
777
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
778
+ rb_check_frozen(self);
779
+ vector_t *vector = get_vector(self);
780
+ rb_need_block();
781
+
782
+ if (!vector_lock_for_update(vector, &timeout)) return Qnil;
783
+ size_t index = vector_assignment_index(vector, raw);
784
+ if (!vector_ensure_capacity(vector, index + 1)) {
785
+ pthread_mutex_unlock(&vector->lock);
786
+ rb_memerror();
787
+ }
788
+ if (index < vector->size && !NIL_P(vector->values[index])) {
789
+ VALUE value = vector->values[index];
790
+ pthread_mutex_unlock(&vector->lock);
791
+ return value;
792
+ }
793
+
794
+ vector_operation_t operation = {
795
+ .self = self,
796
+ .vector = vector,
797
+ .index = index,
798
+ .complete = false,
799
+ };
800
+ vector->updating = true;
801
+ pthread_mutex_unlock(&vector->lock);
802
+ return rb_ensure(
803
+ vector_store_if_absent_body,
804
+ (VALUE)&operation,
805
+ vector_operation_cleanup,
806
+ (VALUE)&operation
807
+ );
808
+ }
809
+
810
+ static VALUE
811
+ vector_cas_body(VALUE opaque)
812
+ {
813
+ vector_operation_t *operation = (vector_operation_t *)opaque;
814
+ bool matches = operation->identity
815
+ ? operation->current == operation->argument
816
+ : RTEST(rb_equal(operation->current, operation->argument));
817
+ rb_check_frozen(operation->self);
818
+
819
+ pthread_mutex_lock(&operation->vector->lock);
820
+ if (matches) operation->vector->values[operation->index] = operation->replacement;
821
+ vector_finish_update_locked(operation->vector);
822
+ pthread_mutex_unlock(&operation->vector->lock);
823
+ operation->complete = true;
824
+ return matches ? Qtrue : Qfalse;
825
+ }
826
+
827
+ static VALUE
828
+ vector_compare_and_set(int argc, VALUE *argv, VALUE self)
829
+ {
830
+ VALUE index_value;
831
+ VALUE expected;
832
+ VALUE replacement;
833
+ VALUE keywords = Qnil;
834
+ rb_scan_args(argc, argv, "3:", &index_value, &expected, &replacement, &keywords);
835
+ rb_check_frozen(self);
836
+ long long raw = vector_convert_index(index_value);
837
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
838
+ rb_check_frozen(self);
839
+ vector_t *vector = get_vector(self);
840
+ containers_check_shareable(expected);
841
+ containers_check_shareable(replacement);
842
+
843
+ if (!vector_lock_for_update(vector, &timeout)) return Qfalse;
844
+ size_t index;
845
+ if (!vector_lookup_index(vector, raw, &index)) {
846
+ pthread_mutex_unlock(&vector->lock);
847
+ return Qfalse;
848
+ }
849
+ vector_operation_t operation = {
850
+ .self = self,
851
+ .vector = vector,
852
+ .index = index,
853
+ .current = vector->values[index],
854
+ .argument = expected,
855
+ .replacement = replacement,
856
+ .identity = vector->compare_by_identity,
857
+ .complete = false,
858
+ };
859
+ vector->updating = true;
860
+ pthread_mutex_unlock(&vector->lock);
861
+ return rb_ensure(vector_cas_body, (VALUE)&operation, vector_operation_cleanup, (VALUE)&operation);
862
+ }
863
+
864
+ static VALUE
865
+ vector_upsert_body(VALUE opaque)
866
+ {
867
+ vector_operation_t *operation = (vector_operation_t *)opaque;
868
+ VALUE result = rb_yield(operation->current);
869
+ rb_check_frozen(operation->self);
870
+ containers_check_shareable(result);
871
+ pthread_mutex_lock(&operation->vector->lock);
872
+ operation->vector->values[operation->index] = result;
873
+ vector_finish_update_locked(operation->vector);
874
+ pthread_mutex_unlock(&operation->vector->lock);
875
+ operation->complete = true;
876
+ return result;
877
+ }
878
+
879
+ static VALUE
880
+ vector_upsert(int argc, VALUE *argv, VALUE self)
881
+ {
882
+ VALUE index_value;
883
+ VALUE initial;
884
+ VALUE keywords = Qnil;
885
+ rb_scan_args(argc, argv, "2:", &index_value, &initial, &keywords);
886
+ rb_check_frozen(self);
887
+ long long raw = vector_convert_index(index_value);
888
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
889
+ rb_check_frozen(self);
890
+ vector_t *vector = get_vector(self);
891
+ containers_check_shareable(initial);
892
+ rb_need_block();
893
+
894
+ if (!vector_lock_for_update(vector, &timeout)) return Qnil;
895
+ size_t index = vector_assignment_index(vector, raw);
896
+ if (!vector_ensure_capacity(vector, index + 1)) {
897
+ pthread_mutex_unlock(&vector->lock);
898
+ rb_memerror();
899
+ }
900
+ if (index >= vector->size) vector->size = index + 1;
901
+ if (NIL_P(vector->values[index])) {
902
+ vector->values[index] = initial;
903
+ vector_notify_waiters_locked(vector);
904
+ pthread_mutex_unlock(&vector->lock);
905
+ return initial;
906
+ }
907
+
908
+ vector_operation_t operation = {
909
+ .self = self,
910
+ .vector = vector,
911
+ .index = index,
912
+ .current = vector->values[index],
913
+ .complete = false,
914
+ };
915
+ vector->updating = true;
916
+ pthread_mutex_unlock(&vector->lock);
917
+ return rb_ensure(vector_upsert_body, (VALUE)&operation, vector_operation_cleanup, (VALUE)&operation);
918
+ }
919
+
920
+ static VALUE
921
+ vector_update_body(VALUE opaque)
922
+ {
923
+ vector_operation_t *operation = (vector_operation_t *)opaque;
924
+ VALUE result = rb_yield(operation->current);
925
+ rb_check_frozen(operation->self);
926
+ containers_check_shareable(result);
927
+ pthread_mutex_lock(&operation->vector->lock);
928
+ if (operation->index >= operation->vector->size) {
929
+ operation->vector->size = operation->index + 1;
930
+ }
931
+ operation->vector->values[operation->index] = result;
932
+ vector_finish_update_locked(operation->vector);
933
+ pthread_mutex_unlock(&operation->vector->lock);
934
+ operation->complete = true;
935
+ return result;
936
+ }
937
+
938
+ static VALUE
939
+ vector_update(int argc, VALUE *argv, VALUE self)
940
+ {
941
+ VALUE index_value;
942
+ VALUE keywords = Qnil;
943
+ rb_scan_args(argc, argv, "1:", &index_value, &keywords);
944
+ rb_check_frozen(self);
945
+ long long raw = vector_convert_index(index_value);
946
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
947
+ rb_check_frozen(self);
948
+ vector_t *vector = get_vector(self);
949
+ rb_need_block();
950
+
951
+ if (!vector_lock_for_update(vector, &timeout)) return Qnil;
952
+ size_t index = vector_assignment_index(vector, raw);
953
+ if (!vector_ensure_capacity(vector, index + 1)) {
954
+ pthread_mutex_unlock(&vector->lock);
955
+ rb_memerror();
956
+ }
957
+
958
+ vector_operation_t operation = {
959
+ .self = self,
960
+ .vector = vector,
961
+ .index = index,
962
+ .current = index < vector->size ? vector->values[index] : Qnil,
963
+ .complete = false,
964
+ };
965
+ vector->updating = true;
966
+ pthread_mutex_unlock(&vector->lock);
967
+ return rb_ensure(vector_update_body, (VALUE)&operation, vector_operation_cleanup, (VALUE)&operation);
968
+ }
969
+
970
+ static bool
971
+ vector_values_equal(vector_t *vector, VALUE left, VALUE right)
972
+ {
973
+ return vector->compare_by_identity ? left == right : RTEST(rb_equal(left, right));
974
+ }
975
+
976
+ static VALUE
977
+ vector_wait_until_changed(int argc, VALUE *argv, VALUE self)
978
+ {
979
+ VALUE index_value;
980
+ VALUE expected;
981
+ VALUE keywords = Qnil;
982
+ rb_scan_args(argc, argv, "2:", &index_value, &expected, &keywords);
983
+ long long raw = vector_convert_index(index_value);
984
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
985
+ vector_t *vector = get_vector(self);
986
+ containers_check_shareable(expected);
987
+
988
+ for (;;) {
989
+ uint64_t generation;
990
+ size_t index;
991
+ pthread_mutex_lock(&vector->lock);
992
+ if (!vector_wait_for_reservation_locked(vector, &timeout)) return Qnil;
993
+ VALUE current = vector_lookup_index(vector, raw, &index) ? vector->values[index] : Qnil;
994
+ generation = vector->generation;
995
+ pthread_mutex_unlock(&vector->lock);
996
+
997
+ if (!vector_values_equal(vector, current, expected)) return current;
998
+
999
+ pthread_mutex_lock(&vector->lock);
1000
+ if (!vector_wait_for_reservation_locked(vector, &timeout)) return Qnil;
1001
+ if (vector->generation != generation) {
1002
+ pthread_mutex_unlock(&vector->lock);
1003
+ continue;
1004
+ }
1005
+ if (!vector_wait_once(vector, &timeout)) return Qnil;
1006
+ }
1007
+ }
1008
+
1009
+ static VALUE
1010
+ vector_wait_until_non_nil(int argc, VALUE *argv, VALUE self)
1011
+ {
1012
+ VALUE index_value;
1013
+ VALUE keywords = Qnil;
1014
+ rb_scan_args(argc, argv, "1:", &index_value, &keywords);
1015
+ long long raw = vector_convert_index(index_value);
1016
+ vector_timeout_t timeout = vector_parse_timeout(vector_timeout_keyword(keywords));
1017
+ vector_t *vector = get_vector(self);
1018
+
1019
+ for (;;) {
1020
+ pthread_mutex_lock(&vector->lock);
1021
+ if (!vector_wait_for_reservation_locked(vector, &timeout)) return Qnil;
1022
+ size_t index;
1023
+ VALUE current = vector_lookup_index(vector, raw, &index) ? vector->values[index] : Qnil;
1024
+ if (!NIL_P(current)) {
1025
+ pthread_mutex_unlock(&vector->lock);
1026
+ return current;
1027
+ }
1028
+ if (!vector_wait_once(vector, &timeout)) return Qnil;
1029
+ }
1030
+ }
1031
+
1032
+ static VALUE
1033
+ unshared_vector_capture_values(VALUE self)
1034
+ {
1035
+ return rb_ivar_get(self, vector_values_id);
1036
+ }
1037
+
1038
+ static VALUE
1039
+ unshared_vector_read_values(VALUE self)
1040
+ {
1041
+ if (rb_ivar_get(self, vector_updating_id) == vector_transaction_marker) {
1042
+ VALUE mutex = rb_ivar_get(self, vector_mutex_id);
1043
+ return rb_mutex_synchronize(mutex, unshared_vector_capture_values, self);
1044
+ }
1045
+ return unshared_vector_capture_values(self);
1046
+ }
1047
+
1048
+ /* An unshared Array is confined to one Ractor. Its reads run under that
1049
+ * Ractor's GVL, so no Ruby mutex is needed between yields on CRuby. */
1050
+ static VALUE
1051
+ unshared_vector_each(VALUE self)
1052
+ {
1053
+ RETURN_ENUMERATOR(self, 0, NULL);
1054
+ VALUE values = unshared_vector_read_values(self);
1055
+ Check_Type(values, T_ARRAY);
1056
+ long limit = RARRAY_LEN(values);
1057
+ for (long index = 0; index < limit && index < RARRAY_LEN(values); index++) {
1058
+ rb_yield(RARRAY_AREF(values, index));
1059
+ }
1060
+ RB_GC_GUARD(values);
1061
+ return self;
1062
+ }
1063
+
1064
+ static VALUE
1065
+ unshared_vector_reverse_each(VALUE self)
1066
+ {
1067
+ RETURN_ENUMERATOR(self, 0, NULL);
1068
+ VALUE values = unshared_vector_read_values(self);
1069
+ Check_Type(values, T_ARRAY);
1070
+ long index = RARRAY_LEN(values);
1071
+ while (index > 0) {
1072
+ if (index > RARRAY_LEN(values)) index = RARRAY_LEN(values);
1073
+ if (index == 0) break;
1074
+ rb_yield(RARRAY_AREF(values, --index));
1075
+ }
1076
+ RB_GC_GUARD(values);
1077
+ return self;
1078
+ }
1079
+
1080
+ static bool
1081
+ vector_transaction_valid(farce_transaction_entry_t *entry)
1082
+ {
1083
+ vector_t *vector = entry->source_data;
1084
+ return vector->generation == entry->version && !vector->updating;
1085
+ }
1086
+
1087
+ static void
1088
+ vector_transaction_apply(farce_transaction_entry_t *entry)
1089
+ {
1090
+ vector_t *vector = entry->source_data;
1091
+ vector_t *copy = entry->working_data;
1092
+ VALUE *values = vector->values;
1093
+ size_t capacity = vector->capacity, size = vector->size;
1094
+ vector->values = copy->values;
1095
+ vector->capacity = copy->capacity;
1096
+ vector->size = copy->size;
1097
+ copy->values = values;
1098
+ copy->capacity = capacity;
1099
+ copy->size = size;
1100
+ }
1101
+
1102
+ static void
1103
+ vector_transaction_notify(farce_transaction_entry_t *entry)
1104
+ {
1105
+ vector_notify_waiters_locked(entry->source_data);
1106
+ }
1107
+
1108
+ static void
1109
+ vector_transaction_reserve(farce_transaction_entry_t *entry, VALUE fiber, VALUE thread)
1110
+ {
1111
+ vector_t *vector = entry->source_data;
1112
+ vector->updating = FARCE_TRANSACTION_RESERVED;
1113
+ vector->updating_fiber = fiber;
1114
+ vector->updating_thread = thread;
1115
+ }
1116
+
1117
+ static void
1118
+ vector_transaction_release(farce_transaction_entry_t *entry)
1119
+ {
1120
+ vector_t *vector = entry->source_data;
1121
+ vector->updating_fiber = Qnil;
1122
+ vector->updating_thread = Qnil;
1123
+ vector_finish_update_locked(vector);
1124
+ }
1125
+
1126
+ static const farce_transaction_ops_t vector_transaction_ops = {
1127
+ vector_transaction_valid, vector_transaction_apply, vector_transaction_notify,
1128
+ vector_transaction_reserve, vector_transaction_release,
1129
+ };
1130
+
1131
+ static VALUE
1132
+ vector_transaction_snapshot(VALUE self)
1133
+ {
1134
+ vector_t *source = get_vector(self);
1135
+ VALUE working = vector_allocate(cVector);
1136
+ vector_t *copy;
1137
+ TypedData_Get_Struct(working, vector_t, &vector_type, copy);
1138
+ farce_transaction_entry_t *entry;
1139
+ VALUE result = farce_transaction_entry_new(
1140
+ self, working, source, copy, &source->lock, &vector_transaction_ops, &entry
1141
+ );
1142
+ pthread_mutex_lock(&source->lock);
1143
+ copy->values = malloc(source->capacity * sizeof(VALUE));
1144
+ if (!copy->values) {
1145
+ pthread_mutex_unlock(&source->lock);
1146
+ rb_memerror();
1147
+ }
1148
+ memcpy(copy->values, source->values, source->size * sizeof(VALUE));
1149
+ for (size_t i = source->size; i < source->capacity; i++) copy->values[i] = Qnil;
1150
+ copy->capacity = source->capacity;
1151
+ copy->size = source->size;
1152
+ copy->compare_by_identity = source->compare_by_identity;
1153
+ copy->initialized = true;
1154
+ entry->version = source->generation;
1155
+ pthread_mutex_unlock(&source->lock);
1156
+ return result;
1157
+ }
1158
+
1159
+ void
1160
+ containers_init_vector(VALUE namespace)
1161
+ {
1162
+ vector_values_id = rb_intern("@values");
1163
+ vector_updating_id = rb_intern("@updating");
1164
+ vector_mutex_id = rb_intern("@mutex");
1165
+ vector_transaction_marker = ID2SYM(rb_intern("transaction"));
1166
+ VALUE iteration = rb_define_module_under(namespace, "UnsharedVectorIteration");
1167
+ rb_define_method(iteration, "each", unshared_vector_each, 0);
1168
+ rb_define_method(iteration, "reverse_each", unshared_vector_reverse_each, 0);
1169
+
1170
+ cVector = rb_define_class_under(namespace, "Vector", rb_cObject);
1171
+ rb_define_alloc_func(cVector, vector_allocate);
1172
+ rb_define_method(cVector, "freeze", vector_freeze, 0);
1173
+ rb_define_method(cVector, "initialize", vector_initialize, -1);
1174
+ rb_define_method(cVector, "size", vector_size, 0);
1175
+ rb_define_method(cVector, "snapshot", vector_snapshot, 0);
1176
+ rb_define_method(cVector, "each", vector_each, 0);
1177
+ rb_define_method(cVector, "reverse_each", vector_reverse_each, 0);
1178
+ rb_define_method(cVector, "fetch", vector_fetch, 1);
1179
+ rb_define_method(cVector, "clear", vector_clear, 0);
1180
+ rb_define_method(cVector, "[]", vector_get_fast, 1);
1181
+ rb_define_method(cVector, "[]=", vector_set_fast, 2);
1182
+ rb_define_method(cVector, "get", vector_get, -1);
1183
+ rb_define_method(cVector, "store", vector_store, -1);
1184
+ rb_define_method(cVector, "push", vector_push, -1);
1185
+ rb_define_method(cVector, "pop", vector_pop, -1);
1186
+ rb_define_method(cVector, "swap", vector_swap, -1);
1187
+ rb_define_method(cVector, "store_if_absent", vector_store_if_absent, -1);
1188
+ rb_define_method(cVector, "transaction_snapshot", vector_transaction_snapshot, 0);
1189
+ rb_define_method(cVector, "compare_and_set", vector_compare_and_set, -1);
1190
+ rb_define_method(cVector, "upsert", vector_upsert, -1);
1191
+ rb_define_method(cVector, "update", vector_update, -1);
1192
+ rb_define_method(cVector, "wait_until_changed", vector_wait_until_changed, -1);
1193
+ rb_define_method(cVector, "wait_until_non_nil", vector_wait_until_non_nil, -1);
1194
+ rb_define_method(cVector, "compare_by_identity?", vector_compare_by_identity_p, 0);
1195
+ }