doc2struct 0.1.0__tar.gz → 0.1.3__tar.gz
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.
- doc2struct-0.1.3/.gitattributes +2 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/.github/workflows/release.yml +4 -4
- {doc2struct-0.1.0 → doc2struct-0.1.3}/.gitignore +2 -1
- {doc2struct-0.1.0 → doc2struct-0.1.3}/CMakeLists.txt +11 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/PKG-INFO +54 -41
- doc2struct-0.1.3/agents.md +1 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/build_scripts/build_pdfium.py +26 -2
- {doc2struct-0.1.0 → doc2struct-0.1.3}/build_scripts/validate_pdfium.py +6 -3
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/CMakeLists.txt +1 -4
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/include/doc2struct/doc2struct.h +1 -1
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/doc2struct.h +17 -3
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/flow.c +13 -3
- doc2struct-0.1.3/c/src/html_pipeline.c +14 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/memory.c +80 -6
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/normalizer.c +147 -48
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/parser.c +1 -1
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/pdf.c +14 -1
- doc2struct-0.1.3/c/src/scan.h +495 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/standardized_text.c +45 -37
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/tables.c +116 -66
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/text.c +112 -7
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/tokenizer.c +64 -205
- doc2struct-0.1.3/c/src/tokenizer_loop.h +211 -0
- doc2struct-0.1.3/c/vendor/pdfium/README.md +30 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/bridge.cpp +6 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/bridge.h +4 -1
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/linux_arm64/doc2struct_pdfium.so +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/linux_arm64/version.json +3 -2
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/linux_x86_64/doc2struct_pdfium.so +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/linux_x86_64/version.json +3 -2
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/macos_arm64/doc2struct_pdfium.dylib +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/macos_arm64/version.json +3 -2
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/macos_x86_64/doc2struct_pdfium.dylib +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/macos_x86_64/version.json +3 -2
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/win_amd64/doc2struct_pdfium.dll +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/win_amd64/version.json +3 -2
- doc2struct-0.1.3/c/vendor/pdfium/text_extraction.patch +787 -0
- doc2struct-0.1.3/c/vendor/pdfium/text_mode.h +26 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/native/module.c +181 -128
- {doc2struct-0.1.0 → doc2struct-0.1.3}/readme.md +53 -40
- doc2struct-0.1.0/c/src/scan.h +0 -220
- {doc2struct-0.1.0 → doc2struct-0.1.3}/LICENSE +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/build_scripts/generate_presets.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/build_scripts/package_native.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/build_scripts/repair_wheel.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/build_scripts/smoke_release.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/bench/test_many.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/bench/text_many.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/doc2structConfig.cmake.in +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/api.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/cli.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/config.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/config_json.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/config_json.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/json.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/lists.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/pdf.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/pdf_layout.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/preset_data.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/rules.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/tags.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/text_layout.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/src/unicode_data.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/AUTHORS.md +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/LICENCE.md +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/SOURCE.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/config.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/config.h.generic +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2.h.generic +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_auto_possess.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_chartables.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_chkdint.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_compile.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_compile.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_compile_cgroup.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_compile_class.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_config.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_context.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_convert.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_dfa_match.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_error.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_extuni.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_find_bracket.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_internal.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_intmodedep.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_jit_char_inc.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_jit_compile.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_jit_match_inc.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_jit_misc_inc.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_jit_simd_inc.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_maketables.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_match.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_match_data.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_match_next.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_newline.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_ord2utf.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_pattern_info.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_printint_inc.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_script_run.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_serialize.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_string_utils.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_study.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_substitute.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_substring.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_tables.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_ucd.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_ucp.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_ucptables_inc.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_util.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_valid_utf.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pcre2/pcre2_xclass.c +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/LICENSE +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/fpdf_text.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/fpdfview.h +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/linux_arm64/licenses/pdfium.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/linux_arm64/licenses/third_party.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/linux_x86_64/licenses/pdfium.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/linux_x86_64/licenses/third_party.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/macos_arm64/licenses/pdfium.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/macos_arm64/licenses/third_party.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/macos_x86_64/licenses/pdfium.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/macos_x86_64/licenses/third_party.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/win_amd64/licenses/pdfium.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/c/vendor/pdfium/runtime/win_amd64/licenses/third_party.txt +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/presets/defaults.json +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/presets/sec_filings.json +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/pyproject.toml +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/__init__.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/_engine.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/convert_html_to_instructions.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/convert_instructions_to_standardized_text.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/convert_partialsgml_to_instructions.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/convert_pdf_to_instructions.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/convert_text_to_instructions.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/html_token_normalizer.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/html_tokenizer.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/parser.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/rules/__init__.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/rules/defaults.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/rules/types.py +0 -0
- {doc2struct-0.1.0 → doc2struct-0.1.3}/python/src/doc2struct/visualizer.py +0 -0
|
@@ -48,7 +48,7 @@ jobs:
|
|
|
48
48
|
- runner: windows-2022
|
|
49
49
|
runtime: win_amd64
|
|
50
50
|
args: ""
|
|
51
|
-
- runner: macos-
|
|
51
|
+
- runner: macos-15
|
|
52
52
|
runtime: macos_arm64
|
|
53
53
|
args: ""
|
|
54
54
|
- runner: macos-15-intel
|
|
@@ -67,7 +67,7 @@ jobs:
|
|
|
67
67
|
id: runtime-cache
|
|
68
68
|
with:
|
|
69
69
|
path: c/vendor/pdfium/runtime/${{ matrix.runtime }}
|
|
70
|
-
key: pdfium-${{ matrix.runner }}-${{ matrix.runtime }}-${{ hashFiles('build_scripts/build_pdfium.py', 'c/vendor/pdfium/bridge.cpp', 'c/vendor/pdfium/bridge.h') }}
|
|
70
|
+
key: pdfium-${{ matrix.runner }}-${{ matrix.runtime }}-${{ hashFiles('build_scripts/build_pdfium.py', 'build_scripts/validate_pdfium.py', 'c/vendor/pdfium/bridge.cpp', 'c/vendor/pdfium/bridge.h', 'c/vendor/pdfium/text_mode.h', 'c/vendor/pdfium/text_extraction.patch') }}
|
|
71
71
|
- name: Build pinned private PDFium once per platform
|
|
72
72
|
if: steps.runtime-cache.outputs.cache-hit != 'true'
|
|
73
73
|
run: python build_scripts/build_pdfium.py --fetch --jobs 4 ${{ matrix.args }}
|
|
@@ -99,7 +99,7 @@ jobs:
|
|
|
99
99
|
- runner: windows-2022
|
|
100
100
|
runtime: win_amd64
|
|
101
101
|
arch: AMD64
|
|
102
|
-
- runner: macos-
|
|
102
|
+
- runner: macos-15
|
|
103
103
|
runtime: macos_arm64
|
|
104
104
|
arch: arm64
|
|
105
105
|
- runner: macos-15-intel
|
|
@@ -139,7 +139,7 @@ jobs:
|
|
|
139
139
|
- runner: windows-2022
|
|
140
140
|
runtime: win_amd64
|
|
141
141
|
platform: win_amd64
|
|
142
|
-
- runner: macos-
|
|
142
|
+
- runner: macos-15
|
|
143
143
|
runtime: macos_arm64
|
|
144
144
|
platform: macos_arm64
|
|
145
145
|
- runner: macos-15-intel
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
cmake_minimum_required(VERSION 3.18)
|
|
2
2
|
project(doc2struct LANGUAGES C)
|
|
3
3
|
option(DOC2STRUCT_BUILD_PYTHON "Build the Python extension" OFF)
|
|
4
|
+
option(DOC2STRUCT_ENABLE_IPO "Enable supported Release link-time optimization" ${DOC2STRUCT_BUILD_PYTHON})
|
|
5
|
+
if(DOC2STRUCT_ENABLE_IPO AND NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION
|
|
6
|
+
AND NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE)
|
|
7
|
+
include(CheckIPOSupported)
|
|
8
|
+
check_ipo_supported(RESULT DOC2STRUCT_IPO_SUPPORTED OUTPUT DOC2STRUCT_IPO_ERROR LANGUAGES C)
|
|
9
|
+
if(DOC2STRUCT_IPO_SUPPORTED)
|
|
10
|
+
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
|
|
11
|
+
else()
|
|
12
|
+
message(STATUS "Link-time optimization unavailable: ${DOC2STRUCT_IPO_ERROR}")
|
|
13
|
+
endif()
|
|
14
|
+
endif()
|
|
4
15
|
add_subdirectory(c)
|
|
5
16
|
|
|
6
17
|
if(DOC2STRUCT_BUILD_PYTHON)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: doc2struct
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Parse HTML, PDF, text, and partial SGML into structured documents in C and Python.
|
|
5
5
|
Author: John Friedman
|
|
6
6
|
License-Expression: MIT
|
|
@@ -24,6 +24,7 @@ doc2struct is an algorithm that can parse documents fast on one thread. It has b
|
|
|
24
24
|

|
|
25
25
|
|
|
26
26
|
**installation**
|
|
27
|
+
|
|
27
28
|
python
|
|
28
29
|
```
|
|
29
30
|
pip install doc2struct
|
|
@@ -38,52 +39,19 @@ cmake --build build --config Release
|
|
|
38
39
|
cmake --install build --config Release --prefix ./install
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
**
|
|
42
|
+
**quickstart**
|
|
42
43
|
|
|
43
44
|
```python
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
standardized_text = parse_partialsgml(text, rules=None)
|
|
49
|
-
|
|
50
|
-
# Convert to instructions
|
|
51
|
-
instructions = convert_html_to_instructions(html, rules=None)
|
|
52
|
-
instructions = convert_pdf_to_instructions(pdf, rules=None)
|
|
53
|
-
instructions = convert_text_to_instructions(text, rules=None)
|
|
54
|
-
instructions = convert_partialsgml_to_instructions(text, rules=None)
|
|
55
|
-
|
|
56
|
-
# Convert instructions to standardized text
|
|
57
|
-
standardized_text = convert_instructions_to_standardized_text(
|
|
58
|
-
instructions, rules=None
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
# Visualize
|
|
62
|
-
visualize_instructions(
|
|
63
|
-
instructions,
|
|
64
|
-
filename="instructions_visualization.html",
|
|
65
|
-
open_browser=True,
|
|
66
|
-
)
|
|
67
|
-
visualize_standardized_text(
|
|
68
|
-
standardized_text,
|
|
69
|
-
filename="standardized_text_visualization.html",
|
|
70
|
-
open_browser=True,
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
# Saving output
|
|
74
|
-
import polars as pl
|
|
75
|
-
from doc2struct import parse_html
|
|
45
|
+
from doc2struct import parse_html, visualize_standardized_text
|
|
46
|
+
# e.g. https://www.sec.gov/Archives/edgar/data/1318605/000095017022000796/tsla-20211231.htm
|
|
47
|
+
with open("10-K.html","rb") as f:
|
|
48
|
+
html = f.read()
|
|
76
49
|
|
|
77
50
|
standardized_text = parse_html(html, rules="SEC:10-K")
|
|
78
|
-
|
|
79
|
-
standardized_text, infer_schema_length=None
|
|
80
|
-
).write_parquet("document.parquet")
|
|
51
|
+
visualize_standardized_text(standardized_text)
|
|
81
52
|
```
|
|
82
53
|
|
|
83
54
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
55
|
It emits a compact data structure, preserving nesting, suitable for storage as parquet.
|
|
88
56
|
|
|
89
57
|
| Column | Meaning | Example |
|
|
@@ -154,6 +122,49 @@ The ideal use case for doc2struct is as part of a [document router](https://data
|
|
|
154
122
|
|
|
155
123
|
The first usecase of doc2struct will be processing every SEC html, pdf, and text file (10TB+) for about $0.04 (AWS spot estimate using c6gd.medium).
|
|
156
124
|
|
|
125
|
+
## Functions
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
# Parse directly to standardized text
|
|
129
|
+
standardized_text = parse_html(html, rules=None)
|
|
130
|
+
standardized_text = parse_pdf(pdf, rules=None)
|
|
131
|
+
standardized_text = parse_text(text, rules=None)
|
|
132
|
+
standardized_text = parse_partialsgml(text, rules=None)
|
|
133
|
+
|
|
134
|
+
# Convert to instructions
|
|
135
|
+
instructions = convert_html_to_instructions(html, rules=None)
|
|
136
|
+
instructions = convert_pdf_to_instructions(pdf, rules=None)
|
|
137
|
+
instructions = convert_text_to_instructions(text, rules=None)
|
|
138
|
+
instructions = convert_partialsgml_to_instructions(text, rules=None)
|
|
139
|
+
|
|
140
|
+
# Convert instructions to standardized text
|
|
141
|
+
standardized_text = convert_instructions_to_standardized_text(
|
|
142
|
+
instructions, rules=None
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Visualize
|
|
146
|
+
visualize_instructions(
|
|
147
|
+
instructions,
|
|
148
|
+
filename="instructions_visualization.html",
|
|
149
|
+
open_browser=True,
|
|
150
|
+
)
|
|
151
|
+
visualize_standardized_text(
|
|
152
|
+
standardized_text,
|
|
153
|
+
filename="standardized_text_visualization.html",
|
|
154
|
+
open_browser=True,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# Saving output
|
|
158
|
+
import polars as pl
|
|
159
|
+
from doc2struct import parse_html
|
|
160
|
+
|
|
161
|
+
standardized_text = parse_html(html, rules="SEC:10-K")
|
|
162
|
+
pl.from_dicts(
|
|
163
|
+
standardized_text, infer_schema_length=None
|
|
164
|
+
).write_parquet("document.parquet")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
|
|
157
168
|
## Modalities supported
|
|
158
169
|
|
|
159
170
|
- HTML
|
|
@@ -457,7 +468,7 @@ It should be fairly easy to add new adapters for different modalities. OCR -> in
|
|
|
457
468
|
- HTML parsing speed benchmarked at 500 MB/s
|
|
458
469
|
- PDF parsing speed benchmarked at 25 MB/s
|
|
459
470
|
- TXT at 60 MB/s
|
|
460
|
-
- Rulesets defined for
|
|
471
|
+
- Rulesets defined for 900+ SEC document types.
|
|
461
472
|
|
|
462
473
|
## Process
|
|
463
474
|
|
|
@@ -471,6 +482,8 @@ It should be fairly easy to add new adapters for different modalities. OCR -> in
|
|
|
471
482
|
|
|
472
483
|
## Benchmarks
|
|
473
484
|
|
|
485
|
+
> Note: since this benchmark was first run, performance has been increased by ~50% on x86.
|
|
486
|
+
|
|
474
487
|
| data | type | size | time | throughput |
|
|
475
488
|
|---|---|---|---|---|
|
|
476
489
|
| Every 2025 10-K and 10-K/A | html | 19,085.105 MB | 39,962 ms | 477.6 MB/s |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
We don't need tests stop adding them.
|
|
@@ -15,6 +15,8 @@ import shutil
|
|
|
15
15
|
import subprocess
|
|
16
16
|
import sys
|
|
17
17
|
|
|
18
|
+
from validate_pdfium import BRIDGE_ABI
|
|
19
|
+
|
|
18
20
|
ROOT=Path(__file__).resolve().parents[1]
|
|
19
21
|
HERE=ROOT/'c/vendor/pdfium'
|
|
20
22
|
SOURCE=ROOT/'build/pdfium'
|
|
@@ -64,6 +66,26 @@ def replace(path, old, new):
|
|
|
64
66
|
path.write_text(text.replace(old,new,1))
|
|
65
67
|
|
|
66
68
|
|
|
69
|
+
def patch_text_extraction():
|
|
70
|
+
patch=HERE/'text_extraction.patch'
|
|
71
|
+
command=['git','apply','--ignore-space-change','--whitespace=nowarn']
|
|
72
|
+
check=subprocess.run([*command,'--check',str(patch)],cwd=SOURCE,capture_output=True,text=True)
|
|
73
|
+
if check.returncode==0:
|
|
74
|
+
subprocess.run([*command,str(patch)],cwd=SOURCE,check=True)
|
|
75
|
+
else:
|
|
76
|
+
applied=subprocess.run([*command,'--reverse','--check',str(patch)],
|
|
77
|
+
cwd=SOURCE,capture_output=True,text=True)
|
|
78
|
+
if applied.returncode:
|
|
79
|
+
raise RuntimeError('Cannot apply the text extraction patch; use a clean checkout of '
|
|
80
|
+
'the pinned PDFium revision.\n'+check.stderr)
|
|
81
|
+
target=SOURCE/'core/fpdfapi/page/doc2struct_text_mode.h'
|
|
82
|
+
contents=(HERE/'text_mode.h').read_text(encoding='utf-8')
|
|
83
|
+
if not target.exists() or target.read_text(encoding='utf-8')!=contents:
|
|
84
|
+
target.write_text(contents,encoding='utf-8')
|
|
85
|
+
replace(SOURCE/'core/fpdfapi/page/BUILD.gn','source_set("page") {\n sources = [',
|
|
86
|
+
'source_set("page") {\n sources = [\n "doc2struct_text_mode.h",')
|
|
87
|
+
|
|
88
|
+
|
|
67
89
|
def runtime_key():
|
|
68
90
|
arch=platform.machine().lower()
|
|
69
91
|
arch={'amd64':'x86_64','aarch64':'arm64'}.get(arch,arch)
|
|
@@ -76,7 +98,7 @@ def bundle(binary, args, key, *, cross=False):
|
|
|
76
98
|
if not cross:
|
|
77
99
|
dll=ctypes.CDLL(str(binary.resolve()))
|
|
78
100
|
dll.DS_PDF_BridgeVersion.restype=ctypes.c_uint
|
|
79
|
-
if dll.DS_PDF_BridgeVersion()!=
|
|
101
|
+
if dll.DS_PDF_BridgeVersion()!=BRIDGE_ABI:
|
|
80
102
|
raise RuntimeError('Unexpected PDFium bridge ABI')
|
|
81
103
|
target=HERE/'runtime'/key
|
|
82
104
|
target.mkdir(parents=True,exist_ok=True)
|
|
@@ -97,7 +119,8 @@ def bundle(binary, args, key, *, cross=False):
|
|
|
97
119
|
parts.append(str(path.relative_to(SOURCE))+'\n\n'+path.read_text(encoding='utf-8',errors='replace'))
|
|
98
120
|
(notices/'third_party.txt').write_text('\n\n'.join(parts),encoding='utf-8')
|
|
99
121
|
metadata=dict(origin='doc2struct',major=149,minor=0,build=7825,patch=0,
|
|
100
|
-
revision=PDFIUM_REVISION,bridge_abi=
|
|
122
|
+
revision=PDFIUM_REVISION,bridge_abi=BRIDGE_ABI,platform=key,
|
|
123
|
+
text_patch_sha256=hashlib.sha256((HERE/'text_extraction.patch').read_bytes()).hexdigest(),
|
|
101
124
|
sha256=hashlib.sha256(binary.read_bytes()).hexdigest(),gn_args=args)
|
|
102
125
|
(target/'version.json').write_text(json.dumps(metadata,indent=2)+'\n')
|
|
103
126
|
print('Bundled '+str(target),flush=True)
|
|
@@ -119,6 +142,7 @@ def main():
|
|
|
119
142
|
if options.fetch: fetch()
|
|
120
143
|
revision=subprocess.check_output(['git','rev-parse','HEAD'],cwd=SOURCE,text=True).strip()
|
|
121
144
|
if revision!=PDFIUM_REVISION: raise RuntimeError('Unexpected PDFium source revision: '+revision)
|
|
145
|
+
patch_text_extraction()
|
|
122
146
|
replace(SOURCE/'.gn','script_executable = "python3"','script_executable = "'+Path(sys.executable).as_posix()+'"')
|
|
123
147
|
for name in ['bridge.cpp','bridge.h']:
|
|
124
148
|
contents=(HERE/name).read_text()
|
|
@@ -5,12 +5,14 @@ import hashlib
|
|
|
5
5
|
import json
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
+
BRIDGE_ABI = 2
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
def validate(binary, *, load=True, licenses=None):
|
|
10
12
|
binary = Path(binary).resolve()
|
|
11
13
|
metadata = json.loads(binary.with_name('version.json').read_text(encoding='utf-8'))
|
|
12
|
-
if metadata.get('bridge_abi') !=
|
|
13
|
-
raise ValueError('PDFium bridge ABI must be
|
|
14
|
+
if metadata.get('bridge_abi') != BRIDGE_ABI:
|
|
15
|
+
raise ValueError(f'PDFium bridge ABI must be {BRIDGE_ABI}')
|
|
14
16
|
if metadata.get('sha256') != hashlib.sha256(binary.read_bytes()).hexdigest():
|
|
15
17
|
raise ValueError('PDFium binary does not match version.json')
|
|
16
18
|
licenses = Path(licenses) if licenses is not None else binary.parent / 'licenses'
|
|
@@ -20,8 +22,9 @@ def validate(binary, *, load=True, licenses=None):
|
|
|
20
22
|
if load:
|
|
21
23
|
runtime = ctypes.CDLL(str(binary))
|
|
22
24
|
runtime.DS_PDF_BridgeVersion.restype = ctypes.c_uint
|
|
23
|
-
if runtime.DS_PDF_BridgeVersion() !=
|
|
25
|
+
if runtime.DS_PDF_BridgeVersion() != BRIDGE_ABI:
|
|
24
26
|
raise ValueError('Unsupported PDFium bridge ABI')
|
|
27
|
+
getattr(runtime, 'DS_PDF_LoadTextPage')
|
|
25
28
|
return metadata
|
|
26
29
|
|
|
27
30
|
|
|
@@ -50,6 +50,7 @@ endif()
|
|
|
50
50
|
add_library(doc2struct STATIC
|
|
51
51
|
src/preset_data.h
|
|
52
52
|
src/api.c
|
|
53
|
+
src/html_pipeline.c
|
|
53
54
|
src/pdf.c
|
|
54
55
|
src/pdf_layout.c
|
|
55
56
|
src/config.c
|
|
@@ -57,13 +58,9 @@ add_library(doc2struct STATIC
|
|
|
57
58
|
src/memory.c
|
|
58
59
|
src/text.c
|
|
59
60
|
src/text_layout.c
|
|
60
|
-
src/tokenizer.c
|
|
61
|
-
src/normalizer.c
|
|
62
61
|
src/rules.c
|
|
63
|
-
src/parser.c
|
|
64
62
|
src/standardized_text.c
|
|
65
63
|
src/lists.c
|
|
66
|
-
src/flow.c
|
|
67
64
|
src/json.c
|
|
68
65
|
src/tables.c
|
|
69
66
|
vendor/pcre2/pcre2_auto_possess.c
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
extern "C" {
|
|
7
7
|
#endif
|
|
8
8
|
|
|
9
|
-
#define DOC2STRUCT_VERSION "0.1.
|
|
9
|
+
#define DOC2STRUCT_VERSION "0.1.3"
|
|
10
10
|
#define DOC2STRUCT_DEFAULT_CACHE_SIZE ((size_t)8 * 1024 * 1024)
|
|
11
11
|
typedef struct doc2struct_rules doc2struct_rules;
|
|
12
12
|
typedef struct doc2struct_parser doc2struct_parser;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include <doc2struct/doc2struct.h>
|
|
4
4
|
#include <stddef.h>
|
|
5
5
|
#include <stdint.h>
|
|
6
|
+
#include <string.h>
|
|
6
7
|
#define PCRE2_CODE_UNIT_WIDTH 8
|
|
7
8
|
#include "pcre2.h"
|
|
8
9
|
|
|
@@ -115,9 +116,15 @@ typedef struct doc2struct_rules {
|
|
|
115
116
|
typedef struct doc2struct_item {
|
|
116
117
|
Run run;
|
|
117
118
|
int fake_table;
|
|
119
|
+
unsigned casing; /* Lazy facts for assembled, immutable instruction text. */
|
|
118
120
|
Vec *hrefs;
|
|
119
121
|
} Item;
|
|
120
122
|
typedef doc2struct_matrix Matrix;
|
|
123
|
+
typedef struct {
|
|
124
|
+
Item *items;
|
|
125
|
+
size_t nitems;
|
|
126
|
+
Str display, rule;
|
|
127
|
+
} TextView;
|
|
121
128
|
typedef struct {
|
|
122
129
|
Item *items;
|
|
123
130
|
size_t nitems;
|
|
@@ -132,6 +139,7 @@ typedef struct {
|
|
|
132
139
|
size_t ntable_cells;
|
|
133
140
|
int layout_text;
|
|
134
141
|
int redundant;
|
|
142
|
+
TextView *text_view;
|
|
135
143
|
} Line;
|
|
136
144
|
|
|
137
145
|
typedef struct ListLines {
|
|
@@ -170,21 +178,27 @@ typedef struct doc2struct_document {
|
|
|
170
178
|
} Document;
|
|
171
179
|
typedef int (*TokenSink)(void *, int, Str, const Attrs *);
|
|
172
180
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
181
|
+
/* Keep these private helpers visible so literal lengths and short comparisons
|
|
182
|
+
* can be folded at each call site without link-time optimization. */
|
|
183
|
+
static inline Str ds_str(const char *s) { return (Str){s, strlen(s)}; }
|
|
184
|
+
static inline int ds_eq(Str a, Str b) {
|
|
185
|
+
return a.n == b.n && (!a.n || !memcmp(a.p, b.p, a.n));
|
|
186
|
+
}
|
|
187
|
+
static inline int ds_is(Str a, const char *s) { return a.p && ds_eq(a, ds_str(s)); }
|
|
176
188
|
void *ds_alloc(Arena *, size_t);
|
|
177
189
|
void *ds_alloc_uninit(Arena *, size_t);
|
|
178
190
|
void ds_arena_free(Arena *);
|
|
179
191
|
void ds_pool_clear(ArenaPool *);
|
|
180
192
|
void *ds_push(Arena *, Vec *, size_t);
|
|
181
193
|
void *ds_map_get(Map *, Str);
|
|
194
|
+
void **ds_map_slot(Arena *, Map *, Str);
|
|
182
195
|
int ds_map_put(Arena *, Map *, Str, void *);
|
|
183
196
|
Str ds_copy(Arena *, Str);
|
|
184
197
|
Str ds_cat(Arena *, Str, Str);
|
|
185
198
|
Str ds_join(Arena *, Str *, size_t, Str);
|
|
186
199
|
Str ds_strip(Str, int);
|
|
187
200
|
Str ds_lower(Arena *, Str);
|
|
201
|
+
Str ds_rule_text(Arena *, Str);
|
|
188
202
|
int ds_space(uint32_t);
|
|
189
203
|
int ds_upper(Str);
|
|
190
204
|
int ds_proper(Str);
|
|
@@ -24,6 +24,8 @@ typedef struct {
|
|
|
24
24
|
typedef struct {
|
|
25
25
|
Document *document;
|
|
26
26
|
Vec items, cells, parts;
|
|
27
|
+
FlowCell **grid;
|
|
28
|
+
size_t grid_cap;
|
|
27
29
|
size_t block;
|
|
28
30
|
size_t max_row, max_col, last_row, last_col;
|
|
29
31
|
int active, table, has_coordinate, unordered;
|
|
@@ -280,9 +282,17 @@ static int table_finish(Flow *flow, Line *line) {
|
|
|
280
282
|
}
|
|
281
283
|
if (nc && nr > SIZE_MAX / nc / sizeof(Str))
|
|
282
284
|
goto large;
|
|
283
|
-
grid
|
|
284
|
-
|
|
285
|
-
|
|
285
|
+
/* This grid is scratch storage. Output items and matrices own their arrays. */
|
|
286
|
+
size_t grid_size = nr * nc;
|
|
287
|
+
if (!flow->grid || grid_size > flow->grid_cap) {
|
|
288
|
+
grid = ds_alloc_uninit(&d->arena, grid_size * sizeof(*grid));
|
|
289
|
+
if (!grid)
|
|
290
|
+
return 0;
|
|
291
|
+
flow->grid = grid;
|
|
292
|
+
flow->grid_cap = grid_size;
|
|
293
|
+
}
|
|
294
|
+
grid = flow->grid;
|
|
295
|
+
memset(grid, 0, grid_size * sizeof(*grid));
|
|
286
296
|
for (i = 0; i < flow->cells.n; i++) {
|
|
287
297
|
FlowCell *cell = cells + i;
|
|
288
298
|
for (y = 0; y < cell->rs; y++)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* Keep the HTML stages together so the tokenizer can call the small text,
|
|
2
|
+
* start and end handlers directly, without changing normalization rules. */
|
|
3
|
+
#if defined(_MSC_VER)
|
|
4
|
+
#define DS_HTML_INLINE __forceinline
|
|
5
|
+
#elif defined(__GNUC__) || defined(__clang__)
|
|
6
|
+
#define DS_HTML_INLINE inline __attribute__((always_inline))
|
|
7
|
+
#else
|
|
8
|
+
#define DS_HTML_INLINE inline
|
|
9
|
+
#endif
|
|
10
|
+
#include "flow.c"
|
|
11
|
+
#include "normalizer.c"
|
|
12
|
+
#include "tokenizer.c"
|
|
13
|
+
#include "parser.c"
|
|
14
|
+
#undef DS_HTML_INLINE
|
|
@@ -15,12 +15,6 @@ struct Block {
|
|
|
15
15
|
Alignment alignment;
|
|
16
16
|
unsigned char data[];
|
|
17
17
|
};
|
|
18
|
-
Str ds_str(const char *s) {
|
|
19
|
-
Str r = {s, strlen(s)};
|
|
20
|
-
return r;
|
|
21
|
-
}
|
|
22
|
-
int ds_eq(Str a, Str b) { return a.n == b.n && (!a.n || !memcmp(a.p, b.p, a.n)); }
|
|
23
|
-
int ds_is(Str a, const char *s) { return a.p && ds_eq(a, ds_str(s)); }
|
|
24
18
|
static Block *pool_take(ArenaPool *pool, size_t capacity) {
|
|
25
19
|
Block **link, **best = NULL, *block;
|
|
26
20
|
if (!pool || !pool->blocks)
|
|
@@ -119,7 +113,46 @@ void *ds_push(Arena *a, Vec *v, size_t width) {
|
|
|
119
113
|
}
|
|
120
114
|
return (char *)v->p + v->n++ * width;
|
|
121
115
|
}
|
|
116
|
+
#if defined(_M_X64)
|
|
117
|
+
#include <intrin.h>
|
|
118
|
+
#include <nmmintrin.h>
|
|
119
|
+
static int crc_available(void) {
|
|
120
|
+
static volatile long cached = -1;
|
|
121
|
+
long result = cached;
|
|
122
|
+
if (result < 0) {
|
|
123
|
+
int registers[4];
|
|
124
|
+
__cpuid(registers, 1);
|
|
125
|
+
result = (registers[2] >> 20) & 1;
|
|
126
|
+
_InterlockedCompareExchange(&cached, result, -1);
|
|
127
|
+
}
|
|
128
|
+
return result != 0;
|
|
129
|
+
}
|
|
130
|
+
static uint64_t crc_string(Str s) {
|
|
131
|
+
uint64_t a = s.n, b = 0x9e3779b1U, c = 0x85ebca77U, d = 0xc2b2ae3dU;
|
|
132
|
+
size_t i = 0;
|
|
133
|
+
for (; s.n - i >= 32; i += 32) {
|
|
134
|
+
uint64_t words[4];
|
|
135
|
+
memcpy(words, s.p + i, sizeof(words));
|
|
136
|
+
a = _mm_crc32_u64(a, words[0]); b = _mm_crc32_u64(b, words[1]);
|
|
137
|
+
c = _mm_crc32_u64(c, words[2]); d = _mm_crc32_u64(d, words[3]);
|
|
138
|
+
}
|
|
139
|
+
for (; s.n - i >= 8; i += 8) {
|
|
140
|
+
uint64_t word;
|
|
141
|
+
memcpy(&word, s.p + i, sizeof(word));
|
|
142
|
+
a = _mm_crc32_u64(a, word);
|
|
143
|
+
}
|
|
144
|
+
for (; i < s.n; i++) a = _mm_crc32_u8((unsigned)a, (unsigned char)s.p[i]);
|
|
145
|
+
uint64_t hash = a ^ (b << 32) ^ ((c << 17) | (c >> 47)) ^ ((d << 43) | (d >> 21));
|
|
146
|
+
hash ^= hash >> 33; hash *= 0xff51afd7ed558ccdULL;
|
|
147
|
+
hash ^= hash >> 33; hash *= 0xc4ceb9fe1a85ec53ULL;
|
|
148
|
+
hash ^= hash >> 33;
|
|
149
|
+
return hash ? hash : 1; /* Zero marks an unused Map entry. */
|
|
150
|
+
}
|
|
151
|
+
#endif
|
|
122
152
|
static uint64_t hash(Str s) {
|
|
153
|
+
#if defined(_M_X64)
|
|
154
|
+
if (s.n >= 32 && crc_available()) return crc_string(s);
|
|
155
|
+
#endif
|
|
123
156
|
uint64_t h = 0x9e3779b97f4a7c15ULL ^ (uint64_t)s.n, word;
|
|
124
157
|
size_t i = 0;
|
|
125
158
|
/* Compare complete keys after hashing; process unaligned words without
|
|
@@ -183,6 +216,47 @@ int ds_map_put(Arena *a, Map *m, Str k, void *value) {
|
|
|
183
216
|
m->entries[i] = (Entry){k, value, h};
|
|
184
217
|
return 1;
|
|
185
218
|
}
|
|
219
|
+
|
|
220
|
+
void **ds_map_slot(Arena *a, Map *m, Str k) {
|
|
221
|
+
size_t i;
|
|
222
|
+
uint64_t h = hash(k);
|
|
223
|
+
/* Resolve existing keys before considering growth; one hash per key. */
|
|
224
|
+
if (m->cap) {
|
|
225
|
+
i = (size_t)h & (m->cap - 1);
|
|
226
|
+
while (m->entries[i].hash) {
|
|
227
|
+
if (m->entries[i].hash == h && ds_eq(m->entries[i].key, k))
|
|
228
|
+
return &m->entries[i].value;
|
|
229
|
+
i = (i + 1) & (m->cap - 1);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (!m->cap || (m->n + 1) * 10 > m->cap * 7) {
|
|
233
|
+
size_t cap = m->cap ? m->cap * 2 : 32, j;
|
|
234
|
+
Entry *entries;
|
|
235
|
+
if (cap < m->cap || cap > SIZE_MAX / sizeof(Entry)) {
|
|
236
|
+
snprintf(a->error, sizeof(a->error), "map too large");
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
entries = ds_alloc(a, cap * sizeof(Entry));
|
|
240
|
+
if (!entries)
|
|
241
|
+
return 0;
|
|
242
|
+
for (j = 0; j < m->cap; j++)
|
|
243
|
+
if (m->entries[j].hash) {
|
|
244
|
+
i = (size_t)m->entries[j].hash & (cap - 1);
|
|
245
|
+
while (entries[i].hash)
|
|
246
|
+
i = (i + 1) & (cap - 1);
|
|
247
|
+
entries[i] = m->entries[j];
|
|
248
|
+
}
|
|
249
|
+
m->entries = entries;
|
|
250
|
+
m->cap = cap;
|
|
251
|
+
}
|
|
252
|
+
i = (size_t)h & (m->cap - 1);
|
|
253
|
+
while (m->entries[i].hash && !ds_eq(m->entries[i].key, k))
|
|
254
|
+
i = (i + 1) & (m->cap - 1);
|
|
255
|
+
if (!m->entries[i].hash)
|
|
256
|
+
m->n++;
|
|
257
|
+
m->entries[i] = (Entry){k, NULL, h};
|
|
258
|
+
return &m->entries[i].value;
|
|
259
|
+
}
|
|
186
260
|
Str ds_copy(Arena *a, Str s) {
|
|
187
261
|
char *p = ds_alloc_uninit(a, s.n + 1);
|
|
188
262
|
if (!p)
|