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
data/ext/farce/dict.c ADDED
@@ -0,0 +1,1523 @@
1
+ /*
2
+ * Dictionary Abstract Data Type
3
+ * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
4
+ *
5
+ * Free Software License:
6
+ *
7
+ * All rights are reserved by the author, with the following exceptions:
8
+ * Permission is granted to freely reproduce and distribute this software,
9
+ * possibly in exchange for a fee, provided that this copyright notice appears
10
+ * intact. Permission is also granted to adapt this software to produce
11
+ * derivative works, as long as the modified versions carry this copyright
12
+ * notice and additional notices stating that the work has been modified.
13
+ * This source code may be translated into executable form and incorporated
14
+ * into proprietary software; there is no requirement for such software to
15
+ * contain a copyright notice related to this source.
16
+ *
17
+ * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $
18
+ * $Name: kazlib_1_20 $
19
+ */
20
+
21
+ /*
22
+ * Modified for Ruby/RBTree.
23
+ * Modified by Farce to support reusing a unique-key insertion search.
24
+ */
25
+
26
+ #include <stdlib.h>
27
+ #include <stddef.h>
28
+ #include <assert.h>
29
+ #define DICT_IMPLEMENTATION
30
+ #include "dict.h"
31
+
32
+ #ifdef KAZLIB_RCSID
33
+ static const char rcsid[] = "$Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $";
34
+ #endif
35
+
36
+ /*
37
+ * These macros provide short convenient names for structure members,
38
+ * which are embellished with dict_ prefixes so that they are
39
+ * properly confined to the documented namespace. It's legal for a
40
+ * program which uses dict to define, for instance, a macro called ``parent''.
41
+ * Such a macro would interfere with the dnode_t struct definition.
42
+ * In general, highly portable and reusable C modules which expose their
43
+ * structures need to confine structure member names to well-defined spaces.
44
+ * The resulting identifiers aren't necessarily convenient to use, nor
45
+ * readable, in the implementation, however!
46
+ */
47
+
48
+ #define left dict_left
49
+ #define right dict_right
50
+ #define parent dict_parent
51
+ #define color dict_color
52
+ #define key dict_key
53
+ #define data dict_data
54
+
55
+ #define nilnode dict_nilnode
56
+ #define nodecount dict_nodecount
57
+ #define compare dict_compare
58
+ #define allocnode dict_allocnode
59
+ #define freenode dict_freenode
60
+ #define context dict_context
61
+ #define dupes dict_dupes
62
+
63
+ #define dictptr dict_dictptr
64
+
65
+ #define dict_root(D) ((D)->nilnode.left)
66
+ #define dict_nil(D) (&(D)->nilnode)
67
+ #define DICT_DEPTH_MAX 64
68
+
69
+ static dnode_t *dnode_alloc(void *context);
70
+ static void dnode_free(dnode_t *node, void *context);
71
+
72
+ /*
73
+ * Perform a ``left rotation'' adjustment on the tree. The given node P and
74
+ * its right child C are rearranged so that the P instead becomes the left
75
+ * child of C. The left subtree of C is inherited as the new right subtree
76
+ * for P. The ordering of the keys within the tree is thus preserved.
77
+ */
78
+
79
+ static void rotate_left(dnode_t *upper)
80
+ {
81
+ dnode_t *lower, *lowleft, *upparent;
82
+
83
+ lower = upper->right;
84
+ upper->right = lowleft = lower->left;
85
+ lowleft->parent = upper;
86
+
87
+ lower->parent = upparent = upper->parent;
88
+
89
+ /* don't need to check for root node here because root->parent is
90
+ the sentinel nil node, and root->parent->left points back to root */
91
+
92
+ if (upper == upparent->left) {
93
+ upparent->left = lower;
94
+ } else {
95
+ assert (upper == upparent->right);
96
+ upparent->right = lower;
97
+ }
98
+
99
+ lower->left = upper;
100
+ upper->parent = lower;
101
+ }
102
+
103
+ /*
104
+ * This operation is the ``mirror'' image of rotate_left. It is
105
+ * the same procedure, but with left and right interchanged.
106
+ */
107
+
108
+ static void rotate_right(dnode_t *upper)
109
+ {
110
+ dnode_t *lower, *lowright, *upparent;
111
+
112
+ lower = upper->left;
113
+ upper->left = lowright = lower->right;
114
+ lowright->parent = upper;
115
+
116
+ lower->parent = upparent = upper->parent;
117
+
118
+ if (upper == upparent->right) {
119
+ upparent->right = lower;
120
+ } else {
121
+ assert (upper == upparent->left);
122
+ upparent->left = lower;
123
+ }
124
+
125
+ lower->right = upper;
126
+ upper->parent = lower;
127
+ }
128
+
129
+ /*
130
+ * Do a postorder traversal of the tree rooted at the specified
131
+ * node and free everything under it. Used by dict_free().
132
+ */
133
+
134
+ static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
135
+ {
136
+ if (node == nil)
137
+ return;
138
+ free_nodes(dict, node->left, nil);
139
+ free_nodes(dict, node->right, nil);
140
+ dict->freenode(node, dict->context);
141
+ }
142
+
143
+ /*
144
+ * This procedure performs a verification that the given subtree is a binary
145
+ * search tree. It performs an inorder traversal of the tree using the
146
+ * dict_next() successor function, verifying that the key of each node is
147
+ * strictly lower than that of its successor, if duplicates are not allowed,
148
+ * or lower or equal if duplicates are allowed. This function is used for
149
+ * debugging purposes.
150
+ */
151
+
152
+ static int verify_bintree(dict_t *dict)
153
+ {
154
+ dnode_t *first, *next;
155
+
156
+ first = dict_first(dict);
157
+
158
+ if (dict->dupes) {
159
+ while (first && (next = dict_next(dict, first))) {
160
+ if (dict->compare(first->key, next->key, dict->context) > 0)
161
+ return 0;
162
+ first = next;
163
+ }
164
+ } else {
165
+ while (first && (next = dict_next(dict, first))) {
166
+ if (dict->compare(first->key, next->key, dict->context) >= 0)
167
+ return 0;
168
+ first = next;
169
+ }
170
+ }
171
+ return 1;
172
+ }
173
+
174
+
175
+ /*
176
+ * This function recursively verifies that the given binary subtree satisfies
177
+ * three of the red black properties. It checks that every red node has only
178
+ * black children. It makes sure that each node is either red or black. And it
179
+ * checks that every path has the same count of black nodes from root to leaf.
180
+ * It returns the blackheight of the given subtree; this allows blackheights to
181
+ * be computed recursively and compared for left and right siblings for
182
+ * mismatches. It does not check for every nil node being black, because there
183
+ * is only one sentinel nil node. The return value of this function is the
184
+ * black height of the subtree rooted at the node ``root'', or zero if the
185
+ * subtree is not red-black.
186
+ */
187
+
188
+ static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
189
+ {
190
+ unsigned height_left, height_right;
191
+
192
+ if (root != nil) {
193
+ height_left = verify_redblack(nil, root->left);
194
+ height_right = verify_redblack(nil, root->right);
195
+ if (height_left == 0 || height_right == 0)
196
+ return 0;
197
+ if (height_left != height_right)
198
+ return 0;
199
+ if (root->color == dnode_red) {
200
+ if (root->left->color != dnode_black)
201
+ return 0;
202
+ if (root->right->color != dnode_black)
203
+ return 0;
204
+ return height_left;
205
+ }
206
+ if (root->color != dnode_black)
207
+ return 0;
208
+ return height_left + 1;
209
+ }
210
+ return 1;
211
+ }
212
+
213
+ /*
214
+ * Compute the actual count of nodes by traversing the tree and
215
+ * return it. This could be compared against the stored count to
216
+ * detect a mismatch.
217
+ */
218
+
219
+ static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
220
+ {
221
+ if (root == nil)
222
+ return 0;
223
+ else
224
+ return 1 + verify_node_count(nil, root->left)
225
+ + verify_node_count(nil, root->right);
226
+ }
227
+
228
+ /*
229
+ * Verify that the tree contains the given node. This is done by
230
+ * traversing all of the nodes and comparing their pointers to the
231
+ * given pointer. Returns 1 if the node is found, otherwise
232
+ * returns zero. It is intended for debugging purposes.
233
+ */
234
+
235
+ static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
236
+ {
237
+ if (root != nil) {
238
+ return root == node
239
+ || verify_dict_has_node(nil, root->left, node)
240
+ || verify_dict_has_node(nil, root->right, node);
241
+ }
242
+ return 0;
243
+ }
244
+
245
+
246
+ /*
247
+ * Dynamically allocate and initialize a dictionary object.
248
+ */
249
+
250
+ dict_t *dict_create(dict_comp_t comp)
251
+ {
252
+ dict_t *new = malloc(sizeof *new);
253
+
254
+ if (new) {
255
+ new->compare = comp;
256
+ new->allocnode = dnode_alloc;
257
+ new->freenode = dnode_free;
258
+ new->context = NULL;
259
+ new->nodecount = 0;
260
+ new->nilnode.left = &new->nilnode;
261
+ new->nilnode.right = &new->nilnode;
262
+ new->nilnode.parent = &new->nilnode;
263
+ new->nilnode.color = dnode_black;
264
+ new->dupes = 0;
265
+ }
266
+ return new;
267
+ }
268
+
269
+ /*
270
+ * Select a different set of node allocator routines.
271
+ */
272
+
273
+ void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
274
+ dnode_free_t fr, void *context)
275
+ {
276
+ assert (dict_count(dict) == 0);
277
+ assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
278
+
279
+ dict->allocnode = al ? al : dnode_alloc;
280
+ dict->freenode = fr ? fr : dnode_free;
281
+ dict->context = context;
282
+ }
283
+
284
+ /*
285
+ * Free a dynamically allocated dictionary object. Removing the nodes
286
+ * from the tree before deleting it is required.
287
+ */
288
+
289
+ void dict_destroy(dict_t *dict)
290
+ {
291
+ assert (dict_isempty(dict));
292
+ free(dict);
293
+ }
294
+
295
+ /*
296
+ * Free all the nodes in the dictionary by using the dictionary's
297
+ * installed free routine. The dictionary is emptied.
298
+ */
299
+
300
+ void dict_free_nodes(dict_t *dict)
301
+ {
302
+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
303
+ free_nodes(dict, root, nil);
304
+ dict->nodecount = 0;
305
+ dict->nilnode.left = &dict->nilnode;
306
+ dict->nilnode.right = &dict->nilnode;
307
+ dict->nilnode.parent = &dict->nilnode;
308
+ }
309
+
310
+ /*
311
+ * Obsolescent function, equivalent to dict_free_nodes
312
+ */
313
+
314
+ void dict_free(dict_t *dict)
315
+ {
316
+ #ifdef KAZLIB_OBSOLESCENT_DEBUG
317
+ assert ("call to obsolescent function dict_free()" && 0);
318
+ #endif
319
+ dict_free_nodes(dict);
320
+ }
321
+
322
+ /*
323
+ * Initialize a user-supplied dictionary object.
324
+ */
325
+
326
+ dict_t *dict_init(dict_t *dict, dict_comp_t comp)
327
+ {
328
+ dict->compare = comp;
329
+ dict->allocnode = dnode_alloc;
330
+ dict->freenode = dnode_free;
331
+ dict->context = NULL;
332
+ dict->nodecount = 0;
333
+ dict->nilnode.left = &dict->nilnode;
334
+ dict->nilnode.right = &dict->nilnode;
335
+ dict->nilnode.parent = &dict->nilnode;
336
+ dict->nilnode.color = dnode_black;
337
+ dict->dupes = 0;
338
+ return dict;
339
+ }
340
+
341
+ /*
342
+ * Initialize a dictionary in the likeness of another dictionary
343
+ */
344
+
345
+ void dict_init_like(dict_t *dict, const dict_t *template)
346
+ {
347
+ dict->compare = template->compare;
348
+ dict->allocnode = template->allocnode;
349
+ dict->freenode = template->freenode;
350
+ dict->context = template->context;
351
+ dict->nodecount = 0;
352
+ dict->nilnode.left = &dict->nilnode;
353
+ dict->nilnode.right = &dict->nilnode;
354
+ dict->nilnode.parent = &dict->nilnode;
355
+ dict->nilnode.color = dnode_black;
356
+ dict->dupes = template->dupes;
357
+
358
+ assert (dict_similar(dict, template));
359
+ }
360
+
361
+ /*
362
+ * Remove all nodes from the dictionary (without freeing them in any way).
363
+ */
364
+
365
+ static void dict_clear(dict_t *dict)
366
+ {
367
+ dict->nodecount = 0;
368
+ dict->nilnode.left = &dict->nilnode;
369
+ dict->nilnode.right = &dict->nilnode;
370
+ dict->nilnode.parent = &dict->nilnode;
371
+ assert (dict->nilnode.color == dnode_black);
372
+ }
373
+
374
+ /*
375
+ * Verify the integrity of the dictionary structure. This is provided for
376
+ * debugging purposes, and should be placed in assert statements. Just because
377
+ * this function succeeds doesn't mean that the tree is not corrupt. Certain
378
+ * corruptions in the tree may simply cause undefined behavior.
379
+ */
380
+
381
+ int dict_verify(dict_t *dict)
382
+ {
383
+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
384
+
385
+ /* check that the sentinel node and root node are black */
386
+ if (root->color != dnode_black)
387
+ return 0;
388
+ if (nil->color != dnode_black)
389
+ return 0;
390
+ if (nil->right != nil)
391
+ return 0;
392
+ /* nil->left is the root node; check that its parent pointer is nil */
393
+ if (nil->left->parent != nil)
394
+ return 0;
395
+ /* perform a weak test that the tree is a binary search tree */
396
+ if (!verify_bintree(dict))
397
+ return 0;
398
+ /* verify that the tree is a red-black tree */
399
+ if (!verify_redblack(nil, root))
400
+ return 0;
401
+ if (verify_node_count(nil, root) != dict_count(dict))
402
+ return 0;
403
+ return 1;
404
+ }
405
+
406
+ /*
407
+ * Determine whether two dictionaries are similar: have the same comparison and
408
+ * allocator functions, and same status as to whether duplicates are allowed.
409
+ */
410
+
411
+ int dict_similar(const dict_t *left, const dict_t *right)
412
+ {
413
+ if (left->compare != right->compare)
414
+ return 0;
415
+
416
+ if (left->allocnode != right->allocnode)
417
+ return 0;
418
+
419
+ if (left->freenode != right->freenode)
420
+ return 0;
421
+
422
+ if (left->context != right->context)
423
+ return 0;
424
+
425
+ return 1;
426
+ }
427
+
428
+ /*
429
+ * Locate a node in the dictionary having the given key.
430
+ * If the node is not found, a null a pointer is returned (rather than
431
+ * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
432
+ * located node is returned.
433
+ */
434
+
435
+ dnode_t *dict_lookup(dict_t *dict, const void *key)
436
+ {
437
+ dnode_t *root = dict_root(dict);
438
+ dnode_t *nil = dict_nil(dict);
439
+ dnode_t *saved;
440
+ int result;
441
+
442
+ /* simple binary search adapted for trees that contain duplicate keys */
443
+
444
+ while (root != nil) {
445
+ result = dict->compare(key, root->key, dict->context);
446
+ if (result < 0)
447
+ root = root->left;
448
+ else if (result > 0)
449
+ root = root->right;
450
+ else {
451
+ if (!dict->dupes) { /* no duplicates, return match */
452
+ return root;
453
+ } else { /* could be dupes, find leftmost one */
454
+ do {
455
+ saved = root;
456
+ root = root->left;
457
+ while (root != nil && dict->compare(key, root->key, dict->context))
458
+ root = root->right;
459
+ } while (root != nil);
460
+ return saved;
461
+ }
462
+ }
463
+ }
464
+
465
+ return NULL;
466
+ }
467
+
468
+ /*
469
+ * Look for the node corresponding to the lowest key that is equal to or
470
+ * greater than the given key. If there is no such node, return null.
471
+ */
472
+
473
+ dnode_t *dict_lower_bound(dict_t *dict, const void *key)
474
+ {
475
+ dnode_t *root = dict_root(dict);
476
+ dnode_t *nil = dict_nil(dict);
477
+ dnode_t *tentative = 0;
478
+
479
+ while (root != nil) {
480
+ int result = dict->compare(key, root->key, dict->context);
481
+
482
+ if (result > 0) {
483
+ root = root->right;
484
+ } else if (result < 0) {
485
+ tentative = root;
486
+ root = root->left;
487
+ } else {
488
+ if (!dict->dupes) {
489
+ return root;
490
+ } else {
491
+ tentative = root;
492
+ root = root->left;
493
+ }
494
+ }
495
+ }
496
+
497
+ return tentative;
498
+ }
499
+
500
+ /*
501
+ * Look for the node corresponding to the greatest key that is equal to or
502
+ * lower than the given key. If there is no such node, return null.
503
+ */
504
+
505
+ dnode_t *dict_upper_bound(dict_t *dict, const void *key)
506
+ {
507
+ dnode_t *root = dict_root(dict);
508
+ dnode_t *nil = dict_nil(dict);
509
+ dnode_t *tentative = 0;
510
+
511
+ while (root != nil) {
512
+ int result = dict->compare(key, root->key, dict->context);
513
+
514
+ if (result < 0) {
515
+ root = root->left;
516
+ } else if (result > 0) {
517
+ tentative = root;
518
+ root = root->right;
519
+ } else {
520
+ if (!dict->dupes) {
521
+ return root;
522
+ } else {
523
+ tentative = root;
524
+ root = root->right;
525
+ }
526
+ }
527
+ }
528
+
529
+ return tentative;
530
+ }
531
+
532
+ /*
533
+ * Insert a node into the dictionary. The node should have been
534
+ * initialized with a data field. All other fields are ignored.
535
+ * The behavior is undefined if the user attempts to insert into
536
+ * a dictionary that is already full (for which the dict_isfull()
537
+ * function returns true).
538
+ */
539
+
540
+ dnode_t *dict_lookup_position(dict_t *dict, const void *key, dnode_t **parent, int *result)
541
+ {
542
+ dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
543
+ assert (!dict->dupes);
544
+ *parent = nil;
545
+ *result = -1;
546
+ while (where != nil) {
547
+ *parent = where;
548
+ *result = dict->compare(key, where->key, dict->context);
549
+ if (*result == 0) return where;
550
+ where = *result < 0 ? where->left : where->right;
551
+ }
552
+ return NULL;
553
+ }
554
+
555
+ int dict_insert(dict_t *dict, dnode_t *node, const void *key)
556
+ {
557
+ dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
558
+ dnode_t *parent = nil;
559
+ int result = -1;
560
+
561
+ node->key = key;
562
+
563
+ assert (!dict_isfull(dict));
564
+ assert (!dict_contains(dict, node));
565
+ assert (!dnode_is_in_a_dict(node));
566
+
567
+ /* basic binary tree insert */
568
+
569
+ while (where != nil) {
570
+ parent = where;
571
+ result = dict->compare(key, where->key, dict->context);
572
+ if (!dict->dupes && result == 0) {
573
+ where->data = node->data;
574
+ return 0;
575
+ } else if (result < 0) {
576
+ where = where->left;
577
+ } else {
578
+ where = where->right;
579
+ }
580
+ }
581
+
582
+ assert (where == nil);
583
+
584
+ return dict_insert_at(dict, node, key, parent, result);
585
+ }
586
+
587
+ int dict_insert_at(dict_t *dict, dnode_t *node, const void *key, dnode_t *parent, int result)
588
+ {
589
+ dnode_t *nil = dict_nil(dict), *uncle, *grandpa;
590
+ node->key = key;
591
+ assert (!dict_isfull(dict));
592
+ assert ((result < 0 ? parent->left : parent->right) == nil);
593
+
594
+ if (result < 0)
595
+ parent->left = node;
596
+ else
597
+ parent->right = node;
598
+
599
+ node->parent = parent;
600
+ node->left = nil;
601
+ node->right = nil;
602
+
603
+ dict->nodecount++;
604
+
605
+ /* red black adjustments */
606
+
607
+ node->color = dnode_red;
608
+
609
+ while (parent->color == dnode_red) {
610
+ grandpa = parent->parent;
611
+ if (parent == grandpa->left) {
612
+ uncle = grandpa->right;
613
+ if (uncle->color == dnode_red) { /* red parent, red uncle */
614
+ parent->color = dnode_black;
615
+ uncle->color = dnode_black;
616
+ grandpa->color = dnode_red;
617
+ node = grandpa;
618
+ parent = grandpa->parent;
619
+ } else { /* red parent, black uncle */
620
+ if (node == parent->right) {
621
+ rotate_left(parent);
622
+ parent = node;
623
+ assert (grandpa == parent->parent);
624
+ /* rotation between parent and child preserves grandpa */
625
+ }
626
+ parent->color = dnode_black;
627
+ grandpa->color = dnode_red;
628
+ rotate_right(grandpa);
629
+ break;
630
+ }
631
+ } else { /* symmetric cases: parent == parent->parent->right */
632
+ uncle = grandpa->left;
633
+ if (uncle->color == dnode_red) {
634
+ parent->color = dnode_black;
635
+ uncle->color = dnode_black;
636
+ grandpa->color = dnode_red;
637
+ node = grandpa;
638
+ parent = grandpa->parent;
639
+ } else {
640
+ if (node == parent->left) {
641
+ rotate_right(parent);
642
+ parent = node;
643
+ assert (grandpa == parent->parent);
644
+ }
645
+ parent->color = dnode_black;
646
+ grandpa->color = dnode_red;
647
+ rotate_left(grandpa);
648
+ break;
649
+ }
650
+ }
651
+ }
652
+
653
+ dict_root(dict)->color = dnode_black;
654
+
655
+ assert (dict_verify(dict));
656
+ return 1;
657
+ }
658
+
659
+ /*
660
+ * Delete the given node from the dictionary. If the given node does not belong
661
+ * to the given dictionary, undefined behavior results. A pointer to the
662
+ * deleted node is returned.
663
+ */
664
+
665
+ dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
666
+ {
667
+ dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent;
668
+
669
+ /* basic deletion */
670
+
671
+ assert (!dict_isempty(dict));
672
+ assert (dict_contains(dict, delete));
673
+
674
+ /*
675
+ * If the node being deleted has two children, then we replace it with its
676
+ * successor (i.e. the leftmost node in the right subtree.) By doing this,
677
+ * we avoid the traditional algorithm under which the successor's key and
678
+ * value *only* move to the deleted node and the successor is spliced out
679
+ * from the tree. We cannot use this approach because the user may hold
680
+ * pointers to the successor, or nodes may be inextricably tied to some
681
+ * other structures by way of embedding, etc. So we must splice out the
682
+ * node we are given, not some other node, and must not move contents from
683
+ * one node to another behind the user's back.
684
+ */
685
+
686
+ if (delete->left != nil && delete->right != nil) {
687
+ dnode_t *next = dict_next(dict, delete);
688
+ dnode_t *nextparent = next->parent;
689
+ dnode_color_t nextcolor = next->color;
690
+
691
+ assert (next != nil);
692
+ assert (next->parent != nil);
693
+ assert (next->left == nil);
694
+
695
+ /*
696
+ * First, splice out the successor from the tree completely, by
697
+ * moving up its right child into its place.
698
+ */
699
+
700
+ child = next->right;
701
+ child->parent = nextparent;
702
+
703
+ if (nextparent->left == next) {
704
+ nextparent->left = child;
705
+ } else {
706
+ assert (nextparent->right == next);
707
+ nextparent->right = child;
708
+ }
709
+
710
+ /*
711
+ * Now that the successor has been extricated from the tree, install it
712
+ * in place of the node that we want deleted.
713
+ */
714
+
715
+ next->parent = delparent;
716
+ next->left = delete->left;
717
+ next->right = delete->right;
718
+ next->left->parent = next;
719
+ next->right->parent = next;
720
+ next->color = delete->color;
721
+ delete->color = nextcolor;
722
+
723
+ if (delparent->left == delete) {
724
+ delparent->left = next;
725
+ } else {
726
+ assert (delparent->right == delete);
727
+ delparent->right = next;
728
+ }
729
+
730
+ } else {
731
+ assert (delete != nil);
732
+ assert (delete->left == nil || delete->right == nil);
733
+
734
+ child = (delete->left != nil) ? delete->left : delete->right;
735
+
736
+ child->parent = delparent = delete->parent;
737
+
738
+ if (delete == delparent->left) {
739
+ delparent->left = child;
740
+ } else {
741
+ assert (delete == delparent->right);
742
+ delparent->right = child;
743
+ }
744
+ }
745
+
746
+ delete->parent = NULL;
747
+ delete->right = NULL;
748
+ delete->left = NULL;
749
+
750
+ dict->nodecount--;
751
+
752
+ assert (verify_bintree(dict));
753
+
754
+ /* red-black adjustments */
755
+
756
+ if (delete->color == dnode_black) {
757
+ dnode_t *parent, *sister;
758
+
759
+ dict_root(dict)->color = dnode_red;
760
+
761
+ while (child->color == dnode_black) {
762
+ parent = child->parent;
763
+ if (child == parent->left) {
764
+ sister = parent->right;
765
+ assert (sister != nil);
766
+ if (sister->color == dnode_red) {
767
+ sister->color = dnode_black;
768
+ parent->color = dnode_red;
769
+ rotate_left(parent);
770
+ sister = parent->right;
771
+ assert (sister != nil);
772
+ }
773
+ if (sister->left->color == dnode_black
774
+ && sister->right->color == dnode_black) {
775
+ sister->color = dnode_red;
776
+ child = parent;
777
+ } else {
778
+ if (sister->right->color == dnode_black) {
779
+ assert (sister->left->color == dnode_red);
780
+ sister->left->color = dnode_black;
781
+ sister->color = dnode_red;
782
+ rotate_right(sister);
783
+ sister = parent->right;
784
+ assert (sister != nil);
785
+ }
786
+ sister->color = parent->color;
787
+ sister->right->color = dnode_black;
788
+ parent->color = dnode_black;
789
+ rotate_left(parent);
790
+ break;
791
+ }
792
+ } else { /* symmetric case: child == child->parent->right */
793
+ assert (child == parent->right);
794
+ sister = parent->left;
795
+ assert (sister != nil);
796
+ if (sister->color == dnode_red) {
797
+ sister->color = dnode_black;
798
+ parent->color = dnode_red;
799
+ rotate_right(parent);
800
+ sister = parent->left;
801
+ assert (sister != nil);
802
+ }
803
+ if (sister->right->color == dnode_black
804
+ && sister->left->color == dnode_black) {
805
+ sister->color = dnode_red;
806
+ child = parent;
807
+ } else {
808
+ if (sister->left->color == dnode_black) {
809
+ assert (sister->right->color == dnode_red);
810
+ sister->right->color = dnode_black;
811
+ sister->color = dnode_red;
812
+ rotate_left(sister);
813
+ sister = parent->left;
814
+ assert (sister != nil);
815
+ }
816
+ sister->color = parent->color;
817
+ sister->left->color = dnode_black;
818
+ parent->color = dnode_black;
819
+ rotate_right(parent);
820
+ break;
821
+ }
822
+ }
823
+ }
824
+
825
+ child->color = dnode_black;
826
+ dict_root(dict)->color = dnode_black;
827
+ }
828
+
829
+ assert (dict_verify(dict));
830
+
831
+ return delete;
832
+ }
833
+
834
+ /*
835
+ * Allocate a node using the dictionary's allocator routine, give it
836
+ * the data item.
837
+ */
838
+
839
+ int dict_alloc_insert(dict_t *dict, const void *key, void *data)
840
+ {
841
+ dnode_t *node = dict->allocnode(dict->context);
842
+
843
+ if (node) {
844
+ dnode_init(node, data);
845
+ if (!dict_insert(dict, node, key))
846
+ dict->freenode(node, dict->context);
847
+ return 1;
848
+ }
849
+ return 0;
850
+ }
851
+
852
+ void dict_delete_free(dict_t *dict, dnode_t *node)
853
+ {
854
+ dict_delete(dict, node);
855
+ dict->freenode(node, dict->context);
856
+ }
857
+
858
+ /*
859
+ * Return the node with the lowest (leftmost) key. If the dictionary is empty
860
+ * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
861
+ */
862
+
863
+ dnode_t *dict_first(dict_t *dict)
864
+ {
865
+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
866
+
867
+ if (root != nil)
868
+ while ((left = root->left) != nil)
869
+ root = left;
870
+
871
+ return (root == nil) ? NULL : root;
872
+ }
873
+
874
+ /*
875
+ * Return the node with the highest (rightmost) key. If the dictionary is empty
876
+ * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
877
+ */
878
+
879
+ dnode_t *dict_last(dict_t *dict)
880
+ {
881
+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right;
882
+
883
+ if (root != nil)
884
+ while ((right = root->right) != nil)
885
+ root = right;
886
+
887
+ return (root == nil) ? NULL : root;
888
+ }
889
+
890
+ /*
891
+ * Return the given node's successor node---the node which has the
892
+ * next key in the the left to right ordering. If the node has
893
+ * no successor, a null pointer is returned rather than a pointer to
894
+ * the nil node.
895
+ */
896
+
897
+ dnode_t *dict_next(dict_t *dict, dnode_t *curr)
898
+ {
899
+ dnode_t *nil = dict_nil(dict), *parent, *left;
900
+
901
+ if (curr->right != nil) {
902
+ curr = curr->right;
903
+ while ((left = curr->left) != nil)
904
+ curr = left;
905
+ return curr;
906
+ }
907
+
908
+ parent = curr->parent;
909
+
910
+ while (parent != nil && curr == parent->right) {
911
+ curr = parent;
912
+ parent = curr->parent;
913
+ }
914
+
915
+ return (parent == nil) ? NULL : parent;
916
+ }
917
+
918
+ /*
919
+ * Return the given node's predecessor, in the key order.
920
+ * The nil sentinel node is returned if there is no predecessor.
921
+ */
922
+
923
+ dnode_t *dict_prev(dict_t *dict, dnode_t *curr)
924
+ {
925
+ dnode_t *nil = dict_nil(dict), *parent, *right;
926
+
927
+ if (curr->left != nil) {
928
+ curr = curr->left;
929
+ while ((right = curr->right) != nil)
930
+ curr = right;
931
+ return curr;
932
+ }
933
+
934
+ parent = curr->parent;
935
+
936
+ while (parent != nil && curr == parent->left) {
937
+ curr = parent;
938
+ parent = curr->parent;
939
+ }
940
+
941
+ return (parent == nil) ? NULL : parent;
942
+ }
943
+
944
+ void dict_allow_dupes(dict_t *dict)
945
+ {
946
+ dict->dupes = 1;
947
+ }
948
+
949
+ #undef dict_count
950
+ #undef dict_isempty
951
+ #undef dict_isfull
952
+ #undef dnode_get
953
+ #undef dnode_put
954
+ #undef dnode_getkey
955
+
956
+ dictcount_t dict_count(dict_t *dict)
957
+ {
958
+ return dict->nodecount;
959
+ }
960
+
961
+ int dict_isempty(dict_t *dict)
962
+ {
963
+ return dict->nodecount == 0;
964
+ }
965
+
966
+ int dict_isfull(dict_t *dict)
967
+ {
968
+ return dict->nodecount == DICTCOUNT_T_MAX;
969
+ }
970
+
971
+ int dict_contains(dict_t *dict, dnode_t *node)
972
+ {
973
+ return verify_dict_has_node(dict_nil(dict), dict_root(dict), node);
974
+ }
975
+
976
+ static dnode_t *dnode_alloc(void *context)
977
+ {
978
+ return malloc(sizeof *dnode_alloc(NULL));
979
+ }
980
+
981
+ static void dnode_free(dnode_t *node, void *context)
982
+ {
983
+ free(node);
984
+ }
985
+
986
+ dnode_t *dnode_create(void *data)
987
+ {
988
+ dnode_t *new = malloc(sizeof *new);
989
+ if (new) {
990
+ new->data = data;
991
+ new->parent = NULL;
992
+ new->left = NULL;
993
+ new->right = NULL;
994
+ }
995
+ return new;
996
+ }
997
+
998
+ dnode_t *dnode_init(dnode_t *dnode, void *data)
999
+ {
1000
+ dnode->data = data;
1001
+ dnode->parent = NULL;
1002
+ dnode->left = NULL;
1003
+ dnode->right = NULL;
1004
+ return dnode;
1005
+ }
1006
+
1007
+ void dnode_destroy(dnode_t *dnode)
1008
+ {
1009
+ assert (!dnode_is_in_a_dict(dnode));
1010
+ free(dnode);
1011
+ }
1012
+
1013
+ void *dnode_get(dnode_t *dnode)
1014
+ {
1015
+ return dnode->data;
1016
+ }
1017
+
1018
+ const void *dnode_getkey(dnode_t *dnode)
1019
+ {
1020
+ return dnode->key;
1021
+ }
1022
+
1023
+ void dnode_put(dnode_t *dnode, void *data)
1024
+ {
1025
+ dnode->data = data;
1026
+ }
1027
+
1028
+ int dnode_is_in_a_dict(dnode_t *dnode)
1029
+ {
1030
+ return (dnode->parent && dnode->left && dnode->right);
1031
+ }
1032
+
1033
+ void dict_process(dict_t *dict, void *context, dnode_process_t function)
1034
+ {
1035
+ dnode_t *node = dict_first(dict), *next;
1036
+
1037
+ while (node != NULL) {
1038
+ /* check for callback function deleting */
1039
+ /* the next node from under us */
1040
+ assert (dict_contains(dict, node));
1041
+ next = dict_next(dict, node);
1042
+ function(dict, node, context);
1043
+ node = next;
1044
+ }
1045
+ }
1046
+
1047
+ static void load_begin_internal(dict_load_t *load, dict_t *dict)
1048
+ {
1049
+ load->dictptr = dict;
1050
+ load->nilnode.left = &load->nilnode;
1051
+ load->nilnode.right = &load->nilnode;
1052
+ }
1053
+
1054
+ void dict_load_begin(dict_load_t *load, dict_t *dict)
1055
+ {
1056
+ assert (dict_isempty(dict));
1057
+ load_begin_internal(load, dict);
1058
+ }
1059
+
1060
+ void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
1061
+ {
1062
+ dict_t *dict = load->dictptr;
1063
+ dnode_t *nil = &load->nilnode;
1064
+
1065
+ assert (!dnode_is_in_a_dict(newnode));
1066
+ assert (dict->nodecount < DICTCOUNT_T_MAX);
1067
+
1068
+ #ifndef NDEBUG
1069
+ if (dict->nodecount > 0) {
1070
+ if (dict->dupes)
1071
+ assert (dict->compare(nil->left->key, key, dict->context) <= 0);
1072
+ else
1073
+ assert (dict->compare(nil->left->key, key, dict->context) < 0);
1074
+ }
1075
+ #endif
1076
+
1077
+ newnode->key = key;
1078
+ nil->right->left = newnode;
1079
+ nil->right = newnode;
1080
+ newnode->left = nil;
1081
+ dict->nodecount++;
1082
+ }
1083
+
1084
+ void dict_load_end(dict_load_t *load)
1085
+ {
1086
+ dict_t *dict = load->dictptr;
1087
+ dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
1088
+ dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next;
1089
+ dnode_t *complete = 0;
1090
+ dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
1091
+ dictcount_t botrowcount;
1092
+ unsigned baselevel = 0, level = 0, i;
1093
+
1094
+ assert (dnode_red == 0 && dnode_black == 1);
1095
+
1096
+ while (fullcount >= nodecount && fullcount)
1097
+ fullcount >>= 1;
1098
+
1099
+ botrowcount = nodecount - fullcount;
1100
+
1101
+ for (curr = loadnil->left; curr != loadnil; curr = next) {
1102
+ next = curr->left;
1103
+
1104
+ if (complete == NULL && botrowcount-- == 0) {
1105
+ assert (baselevel == 0);
1106
+ assert (level == 0);
1107
+ baselevel = level = 1;
1108
+ complete = tree[0];
1109
+
1110
+ if (complete != 0) {
1111
+ tree[0] = 0;
1112
+ complete->right = dictnil;
1113
+ while (tree[level] != 0) {
1114
+ tree[level]->right = complete;
1115
+ complete->parent = tree[level];
1116
+ complete = tree[level];
1117
+ tree[level++] = 0;
1118
+ }
1119
+ }
1120
+ }
1121
+
1122
+ if (complete == NULL) {
1123
+ curr->left = dictnil;
1124
+ curr->right = dictnil;
1125
+ curr->color = level % 2;
1126
+ complete = curr;
1127
+
1128
+ assert (level == baselevel);
1129
+ while (tree[level] != 0) {
1130
+ tree[level]->right = complete;
1131
+ complete->parent = tree[level];
1132
+ complete = tree[level];
1133
+ tree[level++] = 0;
1134
+ }
1135
+ } else {
1136
+ curr->left = complete;
1137
+ curr->color = (level + 1) % 2;
1138
+ complete->parent = curr;
1139
+ tree[level] = curr;
1140
+ complete = 0;
1141
+ level = baselevel;
1142
+ }
1143
+ }
1144
+
1145
+ if (complete == NULL)
1146
+ complete = dictnil;
1147
+
1148
+ for (i = 0; i < DICT_DEPTH_MAX; i++) {
1149
+ if (tree[i] != 0) {
1150
+ tree[i]->right = complete;
1151
+ complete->parent = tree[i];
1152
+ complete = tree[i];
1153
+ }
1154
+ }
1155
+
1156
+ dictnil->color = dnode_black;
1157
+ dictnil->right = dictnil;
1158
+ complete->parent = dictnil;
1159
+ complete->color = dnode_black;
1160
+ dict_root(dict) = complete;
1161
+
1162
+ assert (dict_verify(dict));
1163
+ }
1164
+
1165
+ void dict_merge(dict_t *dest, dict_t *source)
1166
+ {
1167
+ dict_load_t load;
1168
+ dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source);
1169
+
1170
+ assert (dict_similar(dest, source));
1171
+
1172
+ if (source == dest)
1173
+ return;
1174
+
1175
+ dest->nodecount = 0;
1176
+ load_begin_internal(&load, dest);
1177
+
1178
+ for (;;) {
1179
+ if (leftnode != NULL && rightnode != NULL) {
1180
+ if (dest->compare(leftnode->key, rightnode->key, dest->context) < 0)
1181
+ goto copyleft;
1182
+ else
1183
+ goto copyright;
1184
+ } else if (leftnode != NULL) {
1185
+ goto copyleft;
1186
+ } else if (rightnode != NULL) {
1187
+ goto copyright;
1188
+ } else {
1189
+ assert (leftnode == NULL && rightnode == NULL);
1190
+ break;
1191
+ }
1192
+
1193
+ copyleft:
1194
+ {
1195
+ dnode_t *next = dict_next(dest, leftnode);
1196
+ #ifndef NDEBUG
1197
+ leftnode->left = NULL; /* suppress assertion in dict_load_next */
1198
+ #endif
1199
+ dict_load_next(&load, leftnode, leftnode->key);
1200
+ leftnode = next;
1201
+ continue;
1202
+ }
1203
+
1204
+ copyright:
1205
+ {
1206
+ dnode_t *next = dict_next(source, rightnode);
1207
+ #ifndef NDEBUG
1208
+ rightnode->left = NULL;
1209
+ #endif
1210
+ dict_load_next(&load, rightnode, rightnode->key);
1211
+ rightnode = next;
1212
+ continue;
1213
+ }
1214
+ }
1215
+
1216
+ dict_clear(source);
1217
+ dict_load_end(&load);
1218
+ }
1219
+
1220
+ #ifdef KAZLIB_TEST_MAIN
1221
+
1222
+ #include <stdio.h>
1223
+ #include <string.h>
1224
+ #include <ctype.h>
1225
+ #include <stdarg.h>
1226
+
1227
+ typedef char input_t[256];
1228
+
1229
+ static int tokenize(char *string, ...)
1230
+ {
1231
+ char **tokptr;
1232
+ va_list arglist;
1233
+ int tokcount = 0;
1234
+
1235
+ va_start(arglist, string);
1236
+ tokptr = va_arg(arglist, char **);
1237
+ while (tokptr) {
1238
+ while (*string && isspace((unsigned char) *string))
1239
+ string++;
1240
+ if (!*string)
1241
+ break;
1242
+ *tokptr = string;
1243
+ while (*string && !isspace((unsigned char) *string))
1244
+ string++;
1245
+ tokptr = va_arg(arglist, char **);
1246
+ tokcount++;
1247
+ if (!*string)
1248
+ break;
1249
+ *string++ = 0;
1250
+ }
1251
+ va_end(arglist);
1252
+
1253
+ return tokcount;
1254
+ }
1255
+
1256
+ static int comparef(const void *key1, const void *key2)
1257
+ {
1258
+ return strcmp(key1, key2);
1259
+ }
1260
+
1261
+ static char *dupstring(char *str)
1262
+ {
1263
+ int sz = strlen(str) + 1;
1264
+ char *new = malloc(sz);
1265
+ if (new)
1266
+ memcpy(new, str, sz);
1267
+ return new;
1268
+ }
1269
+
1270
+ static dnode_t *new_node(void *c)
1271
+ {
1272
+ static dnode_t few[5];
1273
+ static int count;
1274
+
1275
+ if (count < 5)
1276
+ return few + count++;
1277
+
1278
+ return NULL;
1279
+ }
1280
+
1281
+ static void del_node(dnode_t *n, void *c)
1282
+ {
1283
+ }
1284
+
1285
+ static int prompt = 0;
1286
+
1287
+ static void construct(dict_t *d)
1288
+ {
1289
+ input_t in;
1290
+ int done = 0;
1291
+ dict_load_t dl;
1292
+ dnode_t *dn;
1293
+ char *tok1, *tok2, *val;
1294
+ const char *key;
1295
+ char *help =
1296
+ "p turn prompt on\n"
1297
+ "q finish construction\n"
1298
+ "a <key> <val> add new entry\n";
1299
+
1300
+ if (!dict_isempty(d))
1301
+ puts("warning: dictionary not empty!");
1302
+
1303
+ dict_load_begin(&dl, d);
1304
+
1305
+ while (!done) {
1306
+ if (prompt)
1307
+ putchar('>');
1308
+ fflush(stdout);
1309
+
1310
+ if (!fgets(in, sizeof(input_t), stdin))
1311
+ break;
1312
+
1313
+ switch (in[0]) {
1314
+ case '?':
1315
+ puts(help);
1316
+ break;
1317
+ case 'p':
1318
+ prompt = 1;
1319
+ break;
1320
+ case 'q':
1321
+ done = 1;
1322
+ break;
1323
+ case 'a':
1324
+ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1325
+ puts("what?");
1326
+ break;
1327
+ }
1328
+ key = dupstring(tok1);
1329
+ val = dupstring(tok2);
1330
+ dn = dnode_create(val);
1331
+
1332
+ if (!key || !val || !dn) {
1333
+ puts("out of memory");
1334
+ free((void *) key);
1335
+ free(val);
1336
+ if (dn)
1337
+ dnode_destroy(dn);
1338
+ }
1339
+
1340
+ dict_load_next(&dl, dn, key);
1341
+ break;
1342
+ default:
1343
+ putchar('?');
1344
+ putchar('\n');
1345
+ break;
1346
+ }
1347
+ }
1348
+
1349
+ dict_load_end(&dl);
1350
+ }
1351
+
1352
+ int main(void)
1353
+ {
1354
+ input_t in;
1355
+ dict_t darray[10];
1356
+ dict_t *d = &darray[0];
1357
+ dnode_t *dn;
1358
+ int i;
1359
+ char *tok1, *tok2, *val;
1360
+ const char *key;
1361
+
1362
+ char *help =
1363
+ "a <key> <val> add value to dictionary\n"
1364
+ "d <key> delete value from dictionary\n"
1365
+ "l <key> lookup value in dictionary\n"
1366
+ "( <key> lookup lower bound\n"
1367
+ ") <key> lookup upper bound\n"
1368
+ "# <num> switch to alternate dictionary (0-9)\n"
1369
+ "j <num> <num> merge two dictionaries\n"
1370
+ "f free the whole dictionary\n"
1371
+ "k allow duplicate keys\n"
1372
+ "c show number of entries\n"
1373
+ "t dump whole dictionary in sort order\n"
1374
+ "m make dictionary out of sorted items\n"
1375
+ "p turn prompt on\n"
1376
+ "s switch to non-functioning allocator\n"
1377
+ "q quit";
1378
+
1379
+ for (i = 0; i < sizeof darray / sizeof *darray; i++)
1380
+ dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
1381
+
1382
+ for (;;) {
1383
+ if (prompt)
1384
+ putchar('>');
1385
+ fflush(stdout);
1386
+
1387
+ if (!fgets(in, sizeof(input_t), stdin))
1388
+ break;
1389
+
1390
+ switch(in[0]) {
1391
+ case '?':
1392
+ puts(help);
1393
+ break;
1394
+ case 'a':
1395
+ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1396
+ puts("what?");
1397
+ break;
1398
+ }
1399
+ key = dupstring(tok1);
1400
+ val = dupstring(tok2);
1401
+
1402
+ if (!key || !val) {
1403
+ puts("out of memory");
1404
+ free((void *) key);
1405
+ free(val);
1406
+ }
1407
+
1408
+ if (!dict_alloc_insert(d, key, val)) {
1409
+ puts("dict_alloc_insert failed");
1410
+ free((void *) key);
1411
+ free(val);
1412
+ break;
1413
+ }
1414
+ break;
1415
+ case 'd':
1416
+ if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1417
+ puts("what?");
1418
+ break;
1419
+ }
1420
+ dn = dict_lookup(d, tok1);
1421
+ if (!dn) {
1422
+ puts("dict_lookup failed");
1423
+ break;
1424
+ }
1425
+ val = dnode_get(dn);
1426
+ key = dnode_getkey(dn);
1427
+ dict_delete_free(d, dn);
1428
+
1429
+ free(val);
1430
+ free((void *) key);
1431
+ break;
1432
+ case 'f':
1433
+ dict_free(d);
1434
+ break;
1435
+ case 'l':
1436
+ case '(':
1437
+ case ')':
1438
+ if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1439
+ puts("what?");
1440
+ break;
1441
+ }
1442
+ dn = 0;
1443
+ switch (in[0]) {
1444
+ case 'l':
1445
+ dn = dict_lookup(d, tok1);
1446
+ break;
1447
+ case '(':
1448
+ dn = dict_lower_bound(d, tok1);
1449
+ break;
1450
+ case ')':
1451
+ dn = dict_upper_bound(d, tok1);
1452
+ break;
1453
+ }
1454
+ if (!dn) {
1455
+ puts("lookup failed");
1456
+ break;
1457
+ }
1458
+ val = dnode_get(dn);
1459
+ puts(val);
1460
+ break;
1461
+ case 'm':
1462
+ construct(d);
1463
+ break;
1464
+ case 'k':
1465
+ dict_allow_dupes(d);
1466
+ break;
1467
+ case 'c':
1468
+ printf("%lu\n", (unsigned long) dict_count(d));
1469
+ break;
1470
+ case 't':
1471
+ for (dn = dict_first(d); dn; dn = dict_next(d, dn)) {
1472
+ printf("%s\t%s\n", (char *) dnode_getkey(dn),
1473
+ (char *) dnode_get(dn));
1474
+ }
1475
+ break;
1476
+ case 'q':
1477
+ exit(0);
1478
+ break;
1479
+ case '\0':
1480
+ break;
1481
+ case 'p':
1482
+ prompt = 1;
1483
+ break;
1484
+ case 's':
1485
+ dict_set_allocator(d, new_node, del_node, NULL);
1486
+ break;
1487
+ case '#':
1488
+ if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1489
+ puts("what?");
1490
+ break;
1491
+ } else {
1492
+ int dictnum = atoi(tok1);
1493
+ if (dictnum < 0 || dictnum > 9) {
1494
+ puts("invalid number");
1495
+ break;
1496
+ }
1497
+ d = &darray[dictnum];
1498
+ }
1499
+ break;
1500
+ case 'j':
1501
+ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1502
+ puts("what?");
1503
+ break;
1504
+ } else {
1505
+ int dict1 = atoi(tok1), dict2 = atoi(tok2);
1506
+ if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) {
1507
+ puts("invalid number");
1508
+ break;
1509
+ }
1510
+ dict_merge(&darray[dict1], &darray[dict2]);
1511
+ }
1512
+ break;
1513
+ default:
1514
+ putchar('?');
1515
+ putchar('\n');
1516
+ break;
1517
+ }
1518
+ }
1519
+
1520
+ return 0;
1521
+ }
1522
+
1523
+ #endif