ruby_memprofiler_pprof 0.0.1

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 (200) hide show
  1. checksums.yaml +7 -0
  2. data/ext/ruby_memprofiler_pprof/backtrace.c +429 -0
  3. data/ext/ruby_memprofiler_pprof/collector.c +1055 -0
  4. data/ext/ruby_memprofiler_pprof/compat.c +182 -0
  5. data/ext/ruby_memprofiler_pprof/extconf.rb +72 -0
  6. data/ext/ruby_memprofiler_pprof/pprof.upb.c +170 -0
  7. data/ext/ruby_memprofiler_pprof/pprof.upb.h +848 -0
  8. data/ext/ruby_memprofiler_pprof/pprof_out.c +285 -0
  9. data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.c +11 -0
  10. data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.h +301 -0
  11. data/ext/ruby_memprofiler_pprof/strtab.c +391 -0
  12. data/ext/ruby_memprofiler_pprof/vendor/upb/BUILD +719 -0
  13. data/ext/ruby_memprofiler_pprof/vendor/upb/CONTRIBUTING.md +37 -0
  14. data/ext/ruby_memprofiler_pprof/vendor/upb/DESIGN.md +201 -0
  15. data/ext/ruby_memprofiler_pprof/vendor/upb/LICENSE +26 -0
  16. data/ext/ruby_memprofiler_pprof/vendor/upb/README.md +78 -0
  17. data/ext/ruby_memprofiler_pprof/vendor/upb/WORKSPACE +58 -0
  18. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/BUILD +53 -0
  19. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/amalgamate.py +129 -0
  20. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/build_defs.bzl +160 -0
  21. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/lua.BUILD +127 -0
  22. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/protobuf.patch +54 -0
  23. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/py_proto_library.bzl +137 -0
  24. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/python_downloads.bzl +84 -0
  25. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/system_python.bzl +101 -0
  26. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/upb_proto_library.bzl +388 -0
  27. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/workspace_deps.bzl +89 -0
  28. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/BUILD +252 -0
  29. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/BUILD.googleapis +54 -0
  30. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/benchmark.cc +333 -0
  31. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/build_defs.bzl +88 -0
  32. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/compare.py +118 -0
  33. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/descriptor.proto +888 -0
  34. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/descriptor_sv.proto +890 -0
  35. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/empty.proto +6 -0
  36. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_protobuf_binary_cc.py +64 -0
  37. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_synthetic_protos.py +118 -0
  38. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_upb_binary_c.py +65 -0
  39. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/BUILD.bazel +102 -0
  40. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/README.md +23 -0
  41. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/build_defs.bzl +73 -0
  42. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/make_cmakelists.py +340 -0
  43. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/staleness_test.py +57 -0
  44. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/staleness_test_lib.py +186 -0
  45. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/render.py +43 -0
  46. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/style-guide.md +65 -0
  47. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/vs-cpp-protos.md +255 -0
  48. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/wrapping-upb.md +444 -0
  49. data/ext/ruby_memprofiler_pprof/vendor/upb/python/BUILD +216 -0
  50. data/ext/ruby_memprofiler_pprof/vendor/upb/python/convert.c +394 -0
  51. data/ext/ruby_memprofiler_pprof/vendor/upb/python/convert.h +63 -0
  52. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor.c +1694 -0
  53. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor.h +80 -0
  54. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_containers.c +704 -0
  55. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_containers.h +114 -0
  56. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_pool.c +650 -0
  57. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_pool.h +48 -0
  58. data/ext/ruby_memprofiler_pprof/vendor/upb/python/dist/BUILD.bazel +193 -0
  59. data/ext/ruby_memprofiler_pprof/vendor/upb/python/dist/dist.bzl +190 -0
  60. data/ext/ruby_memprofiler_pprof/vendor/upb/python/extension_dict.c +247 -0
  61. data/ext/ruby_memprofiler_pprof/vendor/upb/python/extension_dict.h +39 -0
  62. data/ext/ruby_memprofiler_pprof/vendor/upb/python/map.c +522 -0
  63. data/ext/ruby_memprofiler_pprof/vendor/upb/python/map.h +66 -0
  64. data/ext/ruby_memprofiler_pprof/vendor/upb/python/message.c +1909 -0
  65. data/ext/ruby_memprofiler_pprof/vendor/upb/python/message.h +101 -0
  66. data/ext/ruby_memprofiler_pprof/vendor/upb/python/minimal_test.py +183 -0
  67. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/BUILD +70 -0
  68. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/README.md +11 -0
  69. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_database_test_wrapper.py +30 -0
  70. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_pool_test_wrapper.py +45 -0
  71. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_test_wrapper.py +46 -0
  72. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/generator_test_wrapper.py +30 -0
  73. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/json_format_test_wrapper.py +30 -0
  74. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/keywords_test_wrapper.py +30 -0
  75. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/message_factory_test_wrapper.py +37 -0
  76. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/message_test_wrapper.py +52 -0
  77. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/proto_builder_test_wrapper.py +32 -0
  78. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/pyproto_test_wrapper.bzl +36 -0
  79. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/reflection_test_wrapper.py +45 -0
  80. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/service_reflection_test_wrapper.py +30 -0
  81. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/symbol_database_test_wrapper.py +30 -0
  82. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/text_encoding_test_wrapper.py +30 -0
  83. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/text_format_test_wrapper.py +30 -0
  84. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/unknown_fields_test_wrapper.py +30 -0
  85. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/well_known_types_test_wrapper.py +36 -0
  86. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/wire_format_test_wrapper.py +30 -0
  87. data/ext/ruby_memprofiler_pprof/vendor/upb/python/protobuf.c +350 -0
  88. data/ext/ruby_memprofiler_pprof/vendor/upb/python/protobuf.h +230 -0
  89. data/ext/ruby_memprofiler_pprof/vendor/upb/python/py_extension.bzl +55 -0
  90. data/ext/ruby_memprofiler_pprof/vendor/upb/python/python_api.h +61 -0
  91. data/ext/ruby_memprofiler_pprof/vendor/upb/python/repeated.c +828 -0
  92. data/ext/ruby_memprofiler_pprof/vendor/upb/python/repeated.h +69 -0
  93. data/ext/ruby_memprofiler_pprof/vendor/upb/python/unknown_fields.c +404 -0
  94. data/ext/ruby_memprofiler_pprof/vendor/upb/python/unknown_fields.h +39 -0
  95. data/ext/ruby_memprofiler_pprof/vendor/upb/python/version_script.lds +6 -0
  96. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/LICENSE +32 -0
  97. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/README.google +9 -0
  98. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/console.lua +156 -0
  99. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/lunit.lua +725 -0
  100. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/BUILD +19 -0
  101. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/LICENSE +21 -0
  102. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/naive.c +92 -0
  103. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/range2-neon.c +157 -0
  104. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/range2-sse.c +170 -0
  105. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/utf8_range.h +9 -0
  106. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/BUILD.bazel +129 -0
  107. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/README.md +8 -0
  108. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/def.c +939 -0
  109. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/lua_proto_library.bzl +138 -0
  110. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/main.c +83 -0
  111. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/msg.c +1118 -0
  112. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/test.proto +69 -0
  113. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/test_upb.lua +846 -0
  114. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.c +258 -0
  115. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.h +132 -0
  116. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.lua +58 -0
  117. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upbc.cc +134 -0
  118. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/collections.c +192 -0
  119. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/collections.h +174 -0
  120. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/conformance_upb.c +346 -0
  121. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/conformance_upb_failures.txt +1 -0
  122. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode.c +1221 -0
  123. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode.h +94 -0
  124. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_fast.c +1055 -0
  125. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_fast.h +153 -0
  126. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_internal.h +211 -0
  127. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.c +3262 -0
  128. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.h +414 -0
  129. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.hpp +438 -0
  130. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/empty.proto +1 -0
  131. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/encode.c +604 -0
  132. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/encode.h +71 -0
  133. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/fuzz/BUILD +13 -0
  134. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/fuzz/file_descriptor_parsenew_fuzzer.cc +43 -0
  135. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_decode.c +1509 -0
  136. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_decode.h +47 -0
  137. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_encode.c +776 -0
  138. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_encode.h +62 -0
  139. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.c +1147 -0
  140. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.h +189 -0
  141. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.hpp +112 -0
  142. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors.c +363 -0
  143. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors.h +263 -0
  144. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors_internal.h +59 -0
  145. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors_test.cc +425 -0
  146. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_test.cc +230 -0
  147. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg.c +428 -0
  148. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg.h +114 -0
  149. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_internal.h +836 -0
  150. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_test.cc +491 -0
  151. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_test.proto +195 -0
  152. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/port_def.inc +261 -0
  153. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/port_undef.inc +62 -0
  154. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.c +323 -0
  155. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.h +109 -0
  156. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.hpp +37 -0
  157. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/table.c +926 -0
  158. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/table_internal.h +385 -0
  159. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test.proto +74 -0
  160. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_cpp.cc +186 -0
  161. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_cpp.proto +12 -0
  162. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_generated_code.cc +977 -0
  163. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_table.cc +580 -0
  164. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/text_encode.c +472 -0
  165. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/text_encode.h +64 -0
  166. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.c +362 -0
  167. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.h +378 -0
  168. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.hpp +115 -0
  169. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb_internal.h +68 -0
  170. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/BUILD +121 -0
  171. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/README.md +7 -0
  172. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare.c +300 -0
  173. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare.h +66 -0
  174. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare_test.cc +236 -0
  175. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto.c +572 -0
  176. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto.h +62 -0
  177. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_public_import_test.proto +32 -0
  178. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_regular_import_test.proto +36 -0
  179. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_test.cc +143 -0
  180. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_test.proto +119 -0
  181. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_weak_import_test.proto +28 -0
  182. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_wweak_import_test.proto +28 -0
  183. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields.c +311 -0
  184. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields.h +94 -0
  185. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields_test.cc +202 -0
  186. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields_test.proto +48 -0
  187. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/BUILD +78 -0
  188. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/common.cc +77 -0
  189. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/common.h +112 -0
  190. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/protoc-gen-upb.cc +1997 -0
  191. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/protoc-gen-upbdefs.cc +193 -0
  192. data/lib/ruby_memprofiler_pprof/atfork.rb +77 -0
  193. data/lib/ruby_memprofiler_pprof/block_flusher.rb +61 -0
  194. data/lib/ruby_memprofiler_pprof/file_flusher.rb +45 -0
  195. data/lib/ruby_memprofiler_pprof/profile_app.rb +30 -0
  196. data/lib/ruby_memprofiler_pprof/profile_data.rb +18 -0
  197. data/lib/ruby_memprofiler_pprof/version.rb +5 -0
  198. data/lib/ruby_memprofiler_pprof.rb +8 -0
  199. data/libexec/ruby_memprofiler_pprof_profile +16 -0
  200. metadata +257 -0
@@ -0,0 +1,926 @@
1
+ /*
2
+ * Copyright (c) 2009-2021, Google LLC
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ * * Redistributions of source code must retain the above copyright
8
+ * notice, this list of conditions and the following disclaimer.
9
+ * * Redistributions in binary form must reproduce the above copyright
10
+ * notice, this list of conditions and the following disclaimer in the
11
+ * documentation and/or other materials provided with the distribution.
12
+ * * Neither the name of Google LLC nor the
13
+ * names of its contributors may be used to endorse or promote products
14
+ * derived from this software without specific prior written permission.
15
+ *
16
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ */
27
+
28
+ /*
29
+ * upb_table Implementation
30
+ *
31
+ * Implementation is heavily inspired by Lua's ltable.c.
32
+ */
33
+
34
+ #include <string.h>
35
+
36
+ #include "upb/table_internal.h"
37
+
38
+ /* Must be last. */
39
+ #include "upb/port_def.inc"
40
+
41
+ #define UPB_MAXARRSIZE 16 /* 64k. */
42
+
43
+ /* From Chromium. */
44
+ #define ARRAY_SIZE(x) \
45
+ ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))
46
+
47
+ static const double MAX_LOAD = 0.85;
48
+
49
+ /* The minimum utilization of the array part of a mixed hash/array table. This
50
+ * is a speed/memory-usage tradeoff (though it's not straightforward because of
51
+ * cache effects). The lower this is, the more memory we'll use. */
52
+ static const double MIN_DENSITY = 0.1;
53
+
54
+ static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; }
55
+
56
+ static upb_value _upb_value_val(uint64_t val) {
57
+ upb_value ret;
58
+ _upb_value_setval(&ret, val);
59
+ return ret;
60
+ }
61
+
62
+ static int log2ceil(uint64_t v) {
63
+ int ret = 0;
64
+ bool pow2 = is_pow2(v);
65
+ while (v >>= 1) ret++;
66
+ ret = pow2 ? ret : ret + 1; /* Ceiling. */
67
+ return UPB_MIN(UPB_MAXARRSIZE, ret);
68
+ }
69
+
70
+ char* upb_strdup2(const char* s, size_t len, upb_Arena* a) {
71
+ size_t n;
72
+ char* p;
73
+
74
+ /* Prevent overflow errors. */
75
+ if (len == SIZE_MAX) return NULL;
76
+ /* Always null-terminate, even if binary data; but don't rely on the input to
77
+ * have a null-terminating byte since it may be a raw binary buffer. */
78
+ n = len + 1;
79
+ p = upb_Arena_Malloc(a, n);
80
+ if (p) {
81
+ memcpy(p, s, len);
82
+ p[len] = 0;
83
+ }
84
+ return p;
85
+ }
86
+
87
+ /* A type to represent the lookup key of either a strtable or an inttable. */
88
+ typedef union {
89
+ uintptr_t num;
90
+ struct {
91
+ const char* str;
92
+ size_t len;
93
+ } str;
94
+ } lookupkey_t;
95
+
96
+ static lookupkey_t strkey2(const char* str, size_t len) {
97
+ lookupkey_t k;
98
+ k.str.str = str;
99
+ k.str.len = len;
100
+ return k;
101
+ }
102
+
103
+ static lookupkey_t intkey(uintptr_t key) {
104
+ lookupkey_t k;
105
+ k.num = key;
106
+ return k;
107
+ }
108
+
109
+ typedef uint32_t hashfunc_t(upb_tabkey key);
110
+ typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2);
111
+
112
+ /* Base table (shared code) ***************************************************/
113
+
114
+ static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; }
115
+
116
+ static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) {
117
+ return t->entries + (hash & t->mask);
118
+ }
119
+
120
+ static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; }
121
+
122
+ static bool isfull(upb_table* t) { return t->count == t->max_count; }
123
+
124
+ static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) {
125
+ size_t bytes;
126
+
127
+ t->count = 0;
128
+ t->size_lg2 = size_lg2;
129
+ t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0;
130
+ t->max_count = upb_table_size(t) * MAX_LOAD;
131
+ bytes = upb_table_size(t) * sizeof(upb_tabent);
132
+ if (bytes > 0) {
133
+ t->entries = upb_Arena_Malloc(a, bytes);
134
+ if (!t->entries) return false;
135
+ memset(t->entries, 0, bytes);
136
+ } else {
137
+ t->entries = NULL;
138
+ }
139
+ return true;
140
+ }
141
+
142
+ static upb_tabent* emptyent(upb_table* t, upb_tabent* e) {
143
+ upb_tabent* begin = t->entries;
144
+ upb_tabent* end = begin + upb_table_size(t);
145
+ for (e = e + 1; e < end; e++) {
146
+ if (upb_tabent_isempty(e)) return e;
147
+ }
148
+ for (e = begin; e < end; e++) {
149
+ if (upb_tabent_isempty(e)) return e;
150
+ }
151
+ UPB_ASSERT(false);
152
+ return NULL;
153
+ }
154
+
155
+ static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) {
156
+ return (upb_tabent*)upb_getentry(t, hash);
157
+ }
158
+
159
+ static const upb_tabent* findentry(const upb_table* t, lookupkey_t key,
160
+ uint32_t hash, eqlfunc_t* eql) {
161
+ const upb_tabent* e;
162
+
163
+ if (t->size_lg2 == 0) return NULL;
164
+ e = upb_getentry(t, hash);
165
+ if (upb_tabent_isempty(e)) return NULL;
166
+ while (1) {
167
+ if (eql(e->key, key)) return e;
168
+ if ((e = e->next) == NULL) return NULL;
169
+ }
170
+ }
171
+
172
+ static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key,
173
+ uint32_t hash, eqlfunc_t* eql) {
174
+ return (upb_tabent*)findentry(t, key, hash, eql);
175
+ }
176
+
177
+ static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v,
178
+ uint32_t hash, eqlfunc_t* eql) {
179
+ const upb_tabent* e = findentry(t, key, hash, eql);
180
+ if (e) {
181
+ if (v) {
182
+ _upb_value_setval(v, e->val.val);
183
+ }
184
+ return true;
185
+ } else {
186
+ return false;
187
+ }
188
+ }
189
+
190
+ /* The given key must not already exist in the table. */
191
+ static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey,
192
+ upb_value val, uint32_t hash, hashfunc_t* hashfunc,
193
+ eqlfunc_t* eql) {
194
+ upb_tabent* mainpos_e;
195
+ upb_tabent* our_e;
196
+
197
+ UPB_ASSERT(findentry(t, key, hash, eql) == NULL);
198
+
199
+ t->count++;
200
+ mainpos_e = getentry_mutable(t, hash);
201
+ our_e = mainpos_e;
202
+
203
+ if (upb_tabent_isempty(mainpos_e)) {
204
+ /* Our main position is empty; use it. */
205
+ our_e->next = NULL;
206
+ } else {
207
+ /* Collision. */
208
+ upb_tabent* new_e = emptyent(t, mainpos_e);
209
+ /* Head of collider's chain. */
210
+ upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key));
211
+ if (chain == mainpos_e) {
212
+ /* Existing ent is in its main position (it has the same hash as us, and
213
+ * is the head of our chain). Insert to new ent and append to this chain.
214
+ */
215
+ new_e->next = mainpos_e->next;
216
+ mainpos_e->next = new_e;
217
+ our_e = new_e;
218
+ } else {
219
+ /* Existing ent is not in its main position (it is a node in some other
220
+ * chain). This implies that no existing ent in the table has our hash.
221
+ * Evict it (updating its chain) and use its ent for head of our chain. */
222
+ *new_e = *mainpos_e; /* copies next. */
223
+ while (chain->next != mainpos_e) {
224
+ chain = (upb_tabent*)chain->next;
225
+ UPB_ASSERT(chain);
226
+ }
227
+ chain->next = new_e;
228
+ our_e = mainpos_e;
229
+ our_e->next = NULL;
230
+ }
231
+ }
232
+ our_e->key = tabkey;
233
+ our_e->val.val = val.val;
234
+ UPB_ASSERT(findentry(t, key, hash, eql) == our_e);
235
+ }
236
+
237
+ static bool rm(upb_table* t, lookupkey_t key, upb_value* val,
238
+ upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) {
239
+ upb_tabent* chain = getentry_mutable(t, hash);
240
+ if (upb_tabent_isempty(chain)) return false;
241
+ if (eql(chain->key, key)) {
242
+ /* Element to remove is at the head of its chain. */
243
+ t->count--;
244
+ if (val) _upb_value_setval(val, chain->val.val);
245
+ if (removed) *removed = chain->key;
246
+ if (chain->next) {
247
+ upb_tabent* move = (upb_tabent*)chain->next;
248
+ *chain = *move;
249
+ move->key = 0; /* Make the slot empty. */
250
+ } else {
251
+ chain->key = 0; /* Make the slot empty. */
252
+ }
253
+ return true;
254
+ } else {
255
+ /* Element to remove is either in a non-head position or not in the
256
+ * table. */
257
+ while (chain->next && !eql(chain->next->key, key)) {
258
+ chain = (upb_tabent*)chain->next;
259
+ }
260
+ if (chain->next) {
261
+ /* Found element to remove. */
262
+ upb_tabent* rm = (upb_tabent*)chain->next;
263
+ t->count--;
264
+ if (val) _upb_value_setval(val, chain->next->val.val);
265
+ if (removed) *removed = rm->key;
266
+ rm->key = 0; /* Make the slot empty. */
267
+ chain->next = rm->next;
268
+ return true;
269
+ } else {
270
+ /* Element to remove is not in the table. */
271
+ return false;
272
+ }
273
+ }
274
+ }
275
+
276
+ static size_t next(const upb_table* t, size_t i) {
277
+ do {
278
+ if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */
279
+ } while (upb_tabent_isempty(&t->entries[i]));
280
+
281
+ return i;
282
+ }
283
+
284
+ static size_t begin(const upb_table* t) { return next(t, -1); }
285
+
286
+ /* upb_strtable ***************************************************************/
287
+
288
+ /* A simple "subclass" of upb_table that only adds a hash function for strings.
289
+ */
290
+
291
+ static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) {
292
+ uint32_t len = (uint32_t)k2.str.len;
293
+ char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1);
294
+ if (str == NULL) return 0;
295
+ memcpy(str, &len, sizeof(uint32_t));
296
+ if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len);
297
+ str[sizeof(uint32_t) + k2.str.len] = '\0';
298
+ return (uintptr_t)str;
299
+ }
300
+
301
+ /* Adapted from ABSL's wyhash. */
302
+
303
+ static uint64_t UnalignedLoad64(const void* p) {
304
+ uint64_t val;
305
+ memcpy(&val, p, 8);
306
+ return val;
307
+ }
308
+
309
+ static uint32_t UnalignedLoad32(const void* p) {
310
+ uint32_t val;
311
+ memcpy(&val, p, 4);
312
+ return val;
313
+ }
314
+
315
+ #if defined(_MSC_VER) && defined(_M_X64)
316
+ #include <intrin.h>
317
+ #endif
318
+
319
+ /* Computes a * b, returning the low 64 bits of the result and storing the high
320
+ * 64 bits in |*high|. */
321
+ static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) {
322
+ #ifdef __SIZEOF_INT128__
323
+ __uint128_t p = v0;
324
+ p *= v1;
325
+ *out_high = (uint64_t)(p >> 64);
326
+ return (uint64_t)p;
327
+ #elif defined(_MSC_VER) && defined(_M_X64)
328
+ return _umul128(v0, v1, out_high);
329
+ #else
330
+ uint64_t a32 = v0 >> 32;
331
+ uint64_t a00 = v0 & 0xffffffff;
332
+ uint64_t b32 = v1 >> 32;
333
+ uint64_t b00 = v1 & 0xffffffff;
334
+ uint64_t high = a32 * b32;
335
+ uint64_t low = a00 * b00;
336
+ uint64_t mid1 = a32 * b00;
337
+ uint64_t mid2 = a00 * b32;
338
+ low += (mid1 << 32) + (mid2 << 32);
339
+ // Omit carry bit, for mixing we do not care about exact numerical precision.
340
+ high += (mid1 >> 32) + (mid2 >> 32);
341
+ *out_high = high;
342
+ return low;
343
+ #endif
344
+ }
345
+
346
+ static uint64_t WyhashMix(uint64_t v0, uint64_t v1) {
347
+ uint64_t high;
348
+ uint64_t low = upb_umul128(v0, v1, &high);
349
+ return low ^ high;
350
+ }
351
+
352
+ static uint64_t Wyhash(const void* data, size_t len, uint64_t seed,
353
+ const uint64_t salt[]) {
354
+ const uint8_t* ptr = (const uint8_t*)data;
355
+ uint64_t starting_length = (uint64_t)len;
356
+ uint64_t current_state = seed ^ salt[0];
357
+
358
+ if (len > 64) {
359
+ // If we have more than 64 bytes, we're going to handle chunks of 64
360
+ // bytes at a time. We're going to build up two separate hash states
361
+ // which we will then hash together.
362
+ uint64_t duplicated_state = current_state;
363
+
364
+ do {
365
+ uint64_t a = UnalignedLoad64(ptr);
366
+ uint64_t b = UnalignedLoad64(ptr + 8);
367
+ uint64_t c = UnalignedLoad64(ptr + 16);
368
+ uint64_t d = UnalignedLoad64(ptr + 24);
369
+ uint64_t e = UnalignedLoad64(ptr + 32);
370
+ uint64_t f = UnalignedLoad64(ptr + 40);
371
+ uint64_t g = UnalignedLoad64(ptr + 48);
372
+ uint64_t h = UnalignedLoad64(ptr + 56);
373
+
374
+ uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state);
375
+ uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state);
376
+ current_state = (cs0 ^ cs1);
377
+
378
+ uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state);
379
+ uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state);
380
+ duplicated_state = (ds0 ^ ds1);
381
+
382
+ ptr += 64;
383
+ len -= 64;
384
+ } while (len > 64);
385
+
386
+ current_state = current_state ^ duplicated_state;
387
+ }
388
+
389
+ // We now have a data `ptr` with at most 64 bytes and the current state
390
+ // of the hashing state machine stored in current_state.
391
+ while (len > 16) {
392
+ uint64_t a = UnalignedLoad64(ptr);
393
+ uint64_t b = UnalignedLoad64(ptr + 8);
394
+
395
+ current_state = WyhashMix(a ^ salt[1], b ^ current_state);
396
+
397
+ ptr += 16;
398
+ len -= 16;
399
+ }
400
+
401
+ // We now have a data `ptr` with at most 16 bytes.
402
+ uint64_t a = 0;
403
+ uint64_t b = 0;
404
+ if (len > 8) {
405
+ // When we have at least 9 and at most 16 bytes, set A to the first 64
406
+ // bits of the input and B to the last 64 bits of the input. Yes, they will
407
+ // overlap in the middle if we are working with less than the full 16
408
+ // bytes.
409
+ a = UnalignedLoad64(ptr);
410
+ b = UnalignedLoad64(ptr + len - 8);
411
+ } else if (len > 3) {
412
+ // If we have at least 4 and at most 8 bytes, set A to the first 32
413
+ // bits and B to the last 32 bits.
414
+ a = UnalignedLoad32(ptr);
415
+ b = UnalignedLoad32(ptr + len - 4);
416
+ } else if (len > 0) {
417
+ // If we have at least 1 and at most 3 bytes, read all of the provided
418
+ // bits into A, with some adjustments.
419
+ a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]);
420
+ b = 0;
421
+ } else {
422
+ a = 0;
423
+ b = 0;
424
+ }
425
+
426
+ uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state);
427
+ uint64_t z = salt[1] ^ starting_length;
428
+ return WyhashMix(w, z);
429
+ }
430
+
431
+ const uint64_t kWyhashSalt[5] = {
432
+ 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL,
433
+ 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL,
434
+ };
435
+
436
+ uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) {
437
+ return Wyhash(p, n, seed, kWyhashSalt);
438
+ }
439
+
440
+ static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) {
441
+ return _upb_Hash(p, n, 0);
442
+ }
443
+
444
+ static uint32_t strhash(upb_tabkey key) {
445
+ uint32_t len;
446
+ char* str = upb_tabstr(key, &len);
447
+ return _upb_Hash_NoSeed(str, len);
448
+ }
449
+
450
+ static bool streql(upb_tabkey k1, lookupkey_t k2) {
451
+ uint32_t len;
452
+ char* str = upb_tabstr(k1, &len);
453
+ return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0);
454
+ }
455
+
456
+ bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) {
457
+ // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2
458
+ // denominator.
459
+ size_t need_entries = (expected_size + 1) * 1204 / 1024;
460
+ UPB_ASSERT(need_entries >= expected_size * 0.85);
461
+ int size_lg2 = _upb_Log2Ceiling(need_entries);
462
+ return init(&t->t, size_lg2, a);
463
+ }
464
+
465
+ void upb_strtable_clear(upb_strtable* t) {
466
+ size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent);
467
+ t->t.count = 0;
468
+ memset((char*)t->t.entries, 0, bytes);
469
+ }
470
+
471
+ bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) {
472
+ upb_strtable new_table;
473
+ upb_strtable_iter i;
474
+
475
+ if (!init(&new_table.t, size_lg2, a)) return false;
476
+ upb_strtable_begin(&i, t);
477
+ for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
478
+ upb_StringView key = upb_strtable_iter_key(&i);
479
+ upb_strtable_insert(&new_table, key.data, key.size,
480
+ upb_strtable_iter_value(&i), a);
481
+ }
482
+ *t = new_table;
483
+ return true;
484
+ }
485
+
486
+ bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len,
487
+ upb_value v, upb_Arena* a) {
488
+ lookupkey_t key;
489
+ upb_tabkey tabkey;
490
+ uint32_t hash;
491
+
492
+ if (isfull(&t->t)) {
493
+ /* Need to resize. New table of double the size, add old elements to it. */
494
+ if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) {
495
+ return false;
496
+ }
497
+ }
498
+
499
+ key = strkey2(k, len);
500
+ tabkey = strcopy(key, a);
501
+ if (tabkey == 0) return false;
502
+
503
+ hash = _upb_Hash_NoSeed(key.str.str, key.str.len);
504
+ insert(&t->t, key, tabkey, v, hash, &strhash, &streql);
505
+ return true;
506
+ }
507
+
508
+ bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len,
509
+ upb_value* v) {
510
+ uint32_t hash = _upb_Hash_NoSeed(key, len);
511
+ return lookup(&t->t, strkey2(key, len), v, hash, &streql);
512
+ }
513
+
514
+ bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len,
515
+ upb_value* val) {
516
+ uint32_t hash = _upb_Hash_NoSeed(key, len);
517
+ upb_tabkey tabkey;
518
+ return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql);
519
+ }
520
+
521
+ /* Iteration */
522
+
523
+ void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) {
524
+ i->t = t;
525
+ i->index = begin(&t->t);
526
+ }
527
+
528
+ void upb_strtable_next(upb_strtable_iter* i) {
529
+ i->index = next(&i->t->t, i->index);
530
+ }
531
+
532
+ bool upb_strtable_done(const upb_strtable_iter* i) {
533
+ if (!i->t) return true;
534
+ return i->index >= upb_table_size(&i->t->t) ||
535
+ upb_tabent_isempty(str_tabent(i));
536
+ }
537
+
538
+ upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) {
539
+ upb_StringView key;
540
+ uint32_t len;
541
+ UPB_ASSERT(!upb_strtable_done(i));
542
+ key.data = upb_tabstr(str_tabent(i)->key, &len);
543
+ key.size = len;
544
+ return key;
545
+ }
546
+
547
+ upb_value upb_strtable_iter_value(const upb_strtable_iter* i) {
548
+ UPB_ASSERT(!upb_strtable_done(i));
549
+ return _upb_value_val(str_tabent(i)->val.val);
550
+ }
551
+
552
+ void upb_strtable_iter_setdone(upb_strtable_iter* i) {
553
+ i->t = NULL;
554
+ i->index = SIZE_MAX;
555
+ }
556
+
557
+ bool upb_strtable_iter_isequal(const upb_strtable_iter* i1,
558
+ const upb_strtable_iter* i2) {
559
+ if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true;
560
+ return i1->t == i2->t && i1->index == i2->index;
561
+ }
562
+
563
+ /* upb_inttable ***************************************************************/
564
+
565
+ /* For inttables we use a hybrid structure where small keys are kept in an
566
+ * array and large keys are put in the hash table. */
567
+
568
+ static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); }
569
+
570
+ static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; }
571
+
572
+ static upb_tabval* mutable_array(upb_inttable* t) {
573
+ return (upb_tabval*)t->array;
574
+ }
575
+
576
+ static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) {
577
+ if (key < t->array_size) {
578
+ return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL;
579
+ } else {
580
+ upb_tabent* e =
581
+ findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql);
582
+ return e ? &e->val : NULL;
583
+ }
584
+ }
585
+
586
+ static const upb_tabval* inttable_val_const(const upb_inttable* t,
587
+ uintptr_t key) {
588
+ return inttable_val((upb_inttable*)t, key);
589
+ }
590
+
591
+ size_t upb_inttable_count(const upb_inttable* t) {
592
+ return t->t.count + t->array_count;
593
+ }
594
+
595
+ static void check(upb_inttable* t) {
596
+ UPB_UNUSED(t);
597
+ #if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG)
598
+ {
599
+ /* This check is very expensive (makes inserts/deletes O(N)). */
600
+ size_t count = 0;
601
+ upb_inttable_iter i;
602
+ upb_inttable_begin(&i, t);
603
+ for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
604
+ UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL));
605
+ }
606
+ UPB_ASSERT(count == upb_inttable_count(t));
607
+ }
608
+ #endif
609
+ }
610
+
611
+ bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2,
612
+ upb_Arena* a) {
613
+ size_t array_bytes;
614
+
615
+ if (!init(&t->t, hsize_lg2, a)) return false;
616
+ /* Always make the array part at least 1 long, so that we know key 0
617
+ * won't be in the hash part, which simplifies things. */
618
+ t->array_size = UPB_MAX(1, asize);
619
+ t->array_count = 0;
620
+ array_bytes = t->array_size * sizeof(upb_value);
621
+ t->array = upb_Arena_Malloc(a, array_bytes);
622
+ if (!t->array) {
623
+ return false;
624
+ }
625
+ memset(mutable_array(t), 0xff, array_bytes);
626
+ check(t);
627
+ return true;
628
+ }
629
+
630
+ bool upb_inttable_init(upb_inttable* t, upb_Arena* a) {
631
+ return upb_inttable_sizedinit(t, 0, 4, a);
632
+ }
633
+
634
+ bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val,
635
+ upb_Arena* a) {
636
+ upb_tabval tabval;
637
+ tabval.val = val.val;
638
+ UPB_ASSERT(
639
+ upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */
640
+
641
+ if (key < t->array_size) {
642
+ UPB_ASSERT(!upb_arrhas(t->array[key]));
643
+ t->array_count++;
644
+ mutable_array(t)[key].val = val.val;
645
+ } else {
646
+ if (isfull(&t->t)) {
647
+ /* Need to resize the hash part, but we re-use the array part. */
648
+ size_t i;
649
+ upb_table new_table;
650
+
651
+ if (!init(&new_table, t->t.size_lg2 + 1, a)) {
652
+ return false;
653
+ }
654
+
655
+ for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) {
656
+ const upb_tabent* e = &t->t.entries[i];
657
+ uint32_t hash;
658
+ upb_value v;
659
+
660
+ _upb_value_setval(&v, e->val.val);
661
+ hash = upb_inthash(e->key);
662
+ insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql);
663
+ }
664
+
665
+ UPB_ASSERT(t->t.count == new_table.count);
666
+
667
+ t->t = new_table;
668
+ }
669
+ insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql);
670
+ }
671
+ check(t);
672
+ return true;
673
+ }
674
+
675
+ bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) {
676
+ const upb_tabval* table_v = inttable_val_const(t, key);
677
+ if (!table_v) return false;
678
+ if (v) _upb_value_setval(v, table_v->val);
679
+ return true;
680
+ }
681
+
682
+ bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) {
683
+ upb_tabval* table_v = inttable_val(t, key);
684
+ if (!table_v) return false;
685
+ table_v->val = val.val;
686
+ return true;
687
+ }
688
+
689
+ bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) {
690
+ bool success;
691
+ if (key < t->array_size) {
692
+ if (upb_arrhas(t->array[key])) {
693
+ upb_tabval empty = UPB_TABVALUE_EMPTY_INIT;
694
+ t->array_count--;
695
+ if (val) {
696
+ _upb_value_setval(val, t->array[key].val);
697
+ }
698
+ mutable_array(t)[key] = empty;
699
+ success = true;
700
+ } else {
701
+ success = false;
702
+ }
703
+ } else {
704
+ success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql);
705
+ }
706
+ check(t);
707
+ return success;
708
+ }
709
+
710
+ void upb_inttable_compact(upb_inttable* t, upb_Arena* a) {
711
+ /* A power-of-two histogram of the table keys. */
712
+ size_t counts[UPB_MAXARRSIZE + 1] = {0};
713
+
714
+ /* The max key in each bucket. */
715
+ uintptr_t max[UPB_MAXARRSIZE + 1] = {0};
716
+
717
+ upb_inttable_iter i;
718
+ size_t arr_count;
719
+ int size_lg2;
720
+ upb_inttable new_t;
721
+
722
+ upb_inttable_begin(&i, t);
723
+ for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
724
+ uintptr_t key = upb_inttable_iter_key(&i);
725
+ int bucket = log2ceil(key);
726
+ max[bucket] = UPB_MAX(max[bucket], key);
727
+ counts[bucket]++;
728
+ }
729
+
730
+ /* Find the largest power of two that satisfies the MIN_DENSITY
731
+ * definition (while actually having some keys). */
732
+ arr_count = upb_inttable_count(t);
733
+
734
+ for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) {
735
+ if (counts[size_lg2] == 0) {
736
+ /* We can halve again without losing any entries. */
737
+ continue;
738
+ } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) {
739
+ break;
740
+ }
741
+
742
+ arr_count -= counts[size_lg2];
743
+ }
744
+
745
+ UPB_ASSERT(arr_count <= upb_inttable_count(t));
746
+
747
+ {
748
+ /* Insert all elements into new, perfectly-sized table. */
749
+ size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */
750
+ size_t hash_count = upb_inttable_count(t) - arr_count;
751
+ size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0;
752
+ int hashsize_lg2 = log2ceil(hash_size);
753
+
754
+ upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a);
755
+ upb_inttable_begin(&i, t);
756
+ for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
757
+ uintptr_t k = upb_inttable_iter_key(&i);
758
+ upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a);
759
+ }
760
+ UPB_ASSERT(new_t.array_size == arr_size);
761
+ UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2);
762
+ }
763
+ *t = new_t;
764
+ }
765
+
766
+ /* Iteration. */
767
+
768
+ static const upb_tabent* int_tabent(const upb_inttable_iter* i) {
769
+ UPB_ASSERT(!i->array_part);
770
+ return &i->t->t.entries[i->index];
771
+ }
772
+
773
+ static upb_tabval int_arrent(const upb_inttable_iter* i) {
774
+ UPB_ASSERT(i->array_part);
775
+ return i->t->array[i->index];
776
+ }
777
+
778
+ void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t) {
779
+ i->t = t;
780
+ i->index = -1;
781
+ i->array_part = true;
782
+ upb_inttable_next(i);
783
+ }
784
+
785
+ void upb_inttable_next(upb_inttable_iter* iter) {
786
+ const upb_inttable* t = iter->t;
787
+ if (iter->array_part) {
788
+ while (++iter->index < t->array_size) {
789
+ if (upb_arrhas(int_arrent(iter))) {
790
+ return;
791
+ }
792
+ }
793
+ iter->array_part = false;
794
+ iter->index = begin(&t->t);
795
+ } else {
796
+ iter->index = next(&t->t, iter->index);
797
+ }
798
+ }
799
+
800
+ bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val,
801
+ intptr_t* iter) {
802
+ intptr_t i = *iter;
803
+ if (i < t->array_size) {
804
+ while (++i < t->array_size) {
805
+ upb_tabval ent = t->array[i];
806
+ if (upb_arrhas(ent)) {
807
+ *key = i;
808
+ *val = _upb_value_val(ent.val);
809
+ *iter = i;
810
+ return true;
811
+ }
812
+ }
813
+ }
814
+
815
+ size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size);
816
+ if (tab_idx < upb_table_size(&t->t)) {
817
+ upb_tabent* ent = &t->t.entries[tab_idx];
818
+ *key = ent->key;
819
+ *val = _upb_value_val(ent->val.val);
820
+ *iter = tab_idx + t->array_size;
821
+ return true;
822
+ }
823
+
824
+ return false;
825
+ }
826
+
827
+ void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) {
828
+ intptr_t i = *iter;
829
+ if (i < t->array_size) {
830
+ t->array_count--;
831
+ mutable_array(t)[i].val = -1;
832
+ } else {
833
+ upb_tabent* ent = &t->t.entries[i - t->array_size];
834
+ upb_tabent* prev = NULL;
835
+
836
+ // Linear search, not great.
837
+ upb_tabent* end = &t->t.entries[upb_table_size(&t->t)];
838
+ for (upb_tabent* e = t->t.entries; e != end; e++) {
839
+ if (e->next == ent) {
840
+ prev = e;
841
+ break;
842
+ }
843
+ }
844
+
845
+ if (prev) {
846
+ prev->next = ent->next;
847
+ }
848
+
849
+ t->t.count--;
850
+ ent->key = 0;
851
+ ent->next = NULL;
852
+ }
853
+ }
854
+
855
+ bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key,
856
+ upb_value* val, intptr_t* iter) {
857
+ size_t tab_idx = next(&t->t, *iter);
858
+ if (tab_idx < upb_table_size(&t->t)) {
859
+ upb_tabent* ent = &t->t.entries[tab_idx];
860
+ uint32_t len;
861
+ key->data = upb_tabstr(ent->key, &len);
862
+ key->size = len;
863
+ *val = _upb_value_val(ent->val.val);
864
+ *iter = tab_idx;
865
+ return true;
866
+ }
867
+
868
+ return false;
869
+ }
870
+
871
+ void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) {
872
+ intptr_t i = *iter;
873
+ upb_tabent* ent = &t->t.entries[i];
874
+ upb_tabent* prev = NULL;
875
+
876
+ // Linear search, not great.
877
+ upb_tabent* end = &t->t.entries[upb_table_size(&t->t)];
878
+ for (upb_tabent* e = t->t.entries; e != end; e++) {
879
+ if (e->next == ent) {
880
+ prev = e;
881
+ break;
882
+ }
883
+ }
884
+
885
+ if (prev) {
886
+ prev->next = ent->next;
887
+ }
888
+
889
+ t->t.count--;
890
+ ent->key = 0;
891
+ ent->next = NULL;
892
+ }
893
+
894
+ bool upb_inttable_done(const upb_inttable_iter* i) {
895
+ if (!i->t) return true;
896
+ if (i->array_part) {
897
+ return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i));
898
+ } else {
899
+ return i->index >= upb_table_size(&i->t->t) ||
900
+ upb_tabent_isempty(int_tabent(i));
901
+ }
902
+ }
903
+
904
+ uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i) {
905
+ UPB_ASSERT(!upb_inttable_done(i));
906
+ return i->array_part ? i->index : int_tabent(i)->key;
907
+ }
908
+
909
+ upb_value upb_inttable_iter_value(const upb_inttable_iter* i) {
910
+ UPB_ASSERT(!upb_inttable_done(i));
911
+ return _upb_value_val(i->array_part ? i->t->array[i->index].val
912
+ : int_tabent(i)->val.val);
913
+ }
914
+
915
+ void upb_inttable_iter_setdone(upb_inttable_iter* i) {
916
+ i->t = NULL;
917
+ i->index = SIZE_MAX;
918
+ i->array_part = false;
919
+ }
920
+
921
+ bool upb_inttable_iter_isequal(const upb_inttable_iter* i1,
922
+ const upb_inttable_iter* i2) {
923
+ if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true;
924
+ return i1->t == i2->t && i1->index == i2->index &&
925
+ i1->array_part == i2->array_part;
926
+ }