redbear 0.1.0__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.
- redbear-0.1.0/.envrc +7 -0
- redbear-0.1.0/.github/workflows/CI.yml +195 -0
- redbear-0.1.0/.gitignore +74 -0
- redbear-0.1.0/Cargo.lock +163 -0
- redbear-0.1.0/Cargo.toml +13 -0
- redbear-0.1.0/PKG-INFO +12 -0
- redbear-0.1.0/README.md +89 -0
- redbear-0.1.0/benchmarks/__init__.py +0 -0
- redbear-0.1.0/benchmarks/blackbear_way.py +26 -0
- redbear-0.1.0/benchmarks/numpy_way.py +28 -0
- redbear-0.1.0/benchmarks/pandas_way.py +28 -0
- redbear-0.1.0/benchmarks/polars_way.py +27 -0
- redbear-0.1.0/benchmarks/redbear_way.py +28 -0
- redbear-0.1.0/flake.lock +61 -0
- redbear-0.1.0/flake.nix +39 -0
- redbear-0.1.0/pyproject.toml +26 -0
- redbear-0.1.0/src/lib.rs +701 -0
redbear-0.1.0/.envrc
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# This file is autogenerated by maturin v1.10.0
|
|
2
|
+
# To update, run
|
|
3
|
+
#
|
|
4
|
+
# maturin generate-ci github
|
|
5
|
+
#
|
|
6
|
+
name: CI
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches:
|
|
11
|
+
- main
|
|
12
|
+
- master
|
|
13
|
+
tags:
|
|
14
|
+
- '*'
|
|
15
|
+
pull_request:
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
test-rust:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- name: Setup Rust
|
|
27
|
+
uses: dtolnay/rust-toolchain@stable
|
|
28
|
+
- name: Run Rust tests
|
|
29
|
+
run: cargo test
|
|
30
|
+
working-directory: .
|
|
31
|
+
linux:
|
|
32
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
33
|
+
needs: test-rust
|
|
34
|
+
strategy:
|
|
35
|
+
matrix:
|
|
36
|
+
platform:
|
|
37
|
+
- runner: ubuntu-22.04
|
|
38
|
+
target: x86_64
|
|
39
|
+
- runner: ubuntu-22.04
|
|
40
|
+
target: x86
|
|
41
|
+
- runner: ubuntu-22.04
|
|
42
|
+
target: aarch64
|
|
43
|
+
- runner: ubuntu-22.04
|
|
44
|
+
target: armv7
|
|
45
|
+
- runner: ubuntu-22.04
|
|
46
|
+
target: s390x
|
|
47
|
+
- runner: ubuntu-22.04
|
|
48
|
+
target: ppc64le
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@v4
|
|
51
|
+
- uses: actions/setup-python@v5
|
|
52
|
+
with:
|
|
53
|
+
python-version: 3.x
|
|
54
|
+
- name: Build wheels
|
|
55
|
+
uses: PyO3/maturin-action@v1
|
|
56
|
+
with:
|
|
57
|
+
target: ${{ matrix.platform.target }}
|
|
58
|
+
args: --release --out dist --find-interpreter
|
|
59
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
60
|
+
manylinux: auto
|
|
61
|
+
- name: Upload wheels
|
|
62
|
+
uses: actions/upload-artifact@v4
|
|
63
|
+
with:
|
|
64
|
+
name: wheels-linux-${{ matrix.platform.target }}
|
|
65
|
+
path: dist
|
|
66
|
+
|
|
67
|
+
musllinux:
|
|
68
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
69
|
+
needs: test-rust
|
|
70
|
+
strategy:
|
|
71
|
+
matrix:
|
|
72
|
+
platform:
|
|
73
|
+
- runner: ubuntu-22.04
|
|
74
|
+
target: x86_64
|
|
75
|
+
- runner: ubuntu-22.04
|
|
76
|
+
target: x86
|
|
77
|
+
- runner: ubuntu-22.04
|
|
78
|
+
target: aarch64
|
|
79
|
+
- runner: ubuntu-22.04
|
|
80
|
+
target: armv7
|
|
81
|
+
steps:
|
|
82
|
+
- uses: actions/checkout@v4
|
|
83
|
+
- uses: actions/setup-python@v5
|
|
84
|
+
with:
|
|
85
|
+
python-version: 3.x
|
|
86
|
+
- name: Build wheels
|
|
87
|
+
uses: PyO3/maturin-action@v1
|
|
88
|
+
with:
|
|
89
|
+
target: ${{ matrix.platform.target }}
|
|
90
|
+
args: --release --out dist --find-interpreter
|
|
91
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
92
|
+
manylinux: musllinux_1_2
|
|
93
|
+
- name: Upload wheels
|
|
94
|
+
uses: actions/upload-artifact@v4
|
|
95
|
+
with:
|
|
96
|
+
name: wheels-musllinux-${{ matrix.platform.target }}
|
|
97
|
+
path: dist
|
|
98
|
+
|
|
99
|
+
windows:
|
|
100
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
101
|
+
needs: test-rust
|
|
102
|
+
strategy:
|
|
103
|
+
matrix:
|
|
104
|
+
platform:
|
|
105
|
+
- runner: windows-latest
|
|
106
|
+
target: x64
|
|
107
|
+
- runner: windows-latest
|
|
108
|
+
target: x86
|
|
109
|
+
steps:
|
|
110
|
+
- uses: actions/checkout@v4
|
|
111
|
+
- uses: actions/setup-python@v5
|
|
112
|
+
with:
|
|
113
|
+
python-version: 3.x
|
|
114
|
+
architecture: ${{ matrix.platform.target }}
|
|
115
|
+
- name: Build wheels
|
|
116
|
+
uses: PyO3/maturin-action@v1
|
|
117
|
+
with:
|
|
118
|
+
target: ${{ matrix.platform.target }}
|
|
119
|
+
args: --release --out dist --find-interpreter
|
|
120
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
121
|
+
- name: Upload wheels
|
|
122
|
+
uses: actions/upload-artifact@v4
|
|
123
|
+
with:
|
|
124
|
+
name: wheels-windows-${{ matrix.platform.target }}
|
|
125
|
+
path: dist
|
|
126
|
+
|
|
127
|
+
macos:
|
|
128
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
129
|
+
needs: test-rust
|
|
130
|
+
strategy:
|
|
131
|
+
matrix:
|
|
132
|
+
platform:
|
|
133
|
+
- runner: macos-14
|
|
134
|
+
target: x86_64
|
|
135
|
+
- runner: macos-14
|
|
136
|
+
target: aarch64
|
|
137
|
+
steps:
|
|
138
|
+
- uses: actions/checkout@v4
|
|
139
|
+
- uses: actions/setup-python@v5
|
|
140
|
+
with:
|
|
141
|
+
python-version: 3.x
|
|
142
|
+
- name: Build wheels
|
|
143
|
+
uses: PyO3/maturin-action@v1
|
|
144
|
+
with:
|
|
145
|
+
target: ${{ matrix.platform.target }}
|
|
146
|
+
args: --release --out dist --find-interpreter
|
|
147
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
148
|
+
- name: Upload wheels
|
|
149
|
+
uses: actions/upload-artifact@v4
|
|
150
|
+
with:
|
|
151
|
+
name: wheels-macos-${{ matrix.platform.target }}
|
|
152
|
+
path: dist
|
|
153
|
+
|
|
154
|
+
sdist:
|
|
155
|
+
runs-on: ubuntu-latest
|
|
156
|
+
needs: test-rust
|
|
157
|
+
steps:
|
|
158
|
+
- uses: actions/checkout@v4
|
|
159
|
+
- name: Build sdist
|
|
160
|
+
uses: PyO3/maturin-action@v1
|
|
161
|
+
with:
|
|
162
|
+
command: sdist
|
|
163
|
+
args: --out dist
|
|
164
|
+
- name: Upload sdist
|
|
165
|
+
uses: actions/upload-artifact@v4
|
|
166
|
+
with:
|
|
167
|
+
name: wheels-sdist
|
|
168
|
+
path: dist
|
|
169
|
+
|
|
170
|
+
release:
|
|
171
|
+
name: Release
|
|
172
|
+
runs-on: ubuntu-latest
|
|
173
|
+
if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
|
|
174
|
+
needs: [test-rust, linux, musllinux, windows, macos, sdist]
|
|
175
|
+
permissions:
|
|
176
|
+
# Use to sign the release artifacts
|
|
177
|
+
id-token: write
|
|
178
|
+
# Used to upload release artifacts
|
|
179
|
+
contents: write
|
|
180
|
+
# Used to generate artifact attestation
|
|
181
|
+
attestations: write
|
|
182
|
+
steps:
|
|
183
|
+
- uses: actions/download-artifact@v4
|
|
184
|
+
- name: Generate artifact attestation
|
|
185
|
+
uses: actions/attest-build-provenance@v2
|
|
186
|
+
with:
|
|
187
|
+
subject-path: 'wheels-*/*'
|
|
188
|
+
- name: Publish to PyPI
|
|
189
|
+
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
|
190
|
+
uses: PyO3/maturin-action@v1
|
|
191
|
+
env:
|
|
192
|
+
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
193
|
+
with:
|
|
194
|
+
command: upload
|
|
195
|
+
args: --non-interactive --skip-existing wheels-*/*
|
redbear-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/target
|
|
2
|
+
|
|
3
|
+
# Byte-compiled / optimized / DLL files
|
|
4
|
+
__pycache__/
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
|
|
8
|
+
# C extensions
|
|
9
|
+
*.so
|
|
10
|
+
|
|
11
|
+
# Distribution / packaging
|
|
12
|
+
.Python
|
|
13
|
+
.venv/
|
|
14
|
+
env/
|
|
15
|
+
bin/
|
|
16
|
+
build/
|
|
17
|
+
develop-eggs/
|
|
18
|
+
dist/
|
|
19
|
+
eggs/
|
|
20
|
+
lib/
|
|
21
|
+
lib64/
|
|
22
|
+
parts/
|
|
23
|
+
sdist/
|
|
24
|
+
var/
|
|
25
|
+
include/
|
|
26
|
+
man/
|
|
27
|
+
venv/
|
|
28
|
+
*.egg-info/
|
|
29
|
+
.installed.cfg
|
|
30
|
+
*.egg
|
|
31
|
+
|
|
32
|
+
# Installer logs
|
|
33
|
+
pip-log.txt
|
|
34
|
+
pip-delete-this-directory.txt
|
|
35
|
+
pip-selfcheck.json
|
|
36
|
+
|
|
37
|
+
# Unit test / coverage reports
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.coverage
|
|
41
|
+
.cache
|
|
42
|
+
nosetests.xml
|
|
43
|
+
coverage.xml
|
|
44
|
+
|
|
45
|
+
# Translations
|
|
46
|
+
*.mo
|
|
47
|
+
|
|
48
|
+
# Mr Developer
|
|
49
|
+
.mr.developer.cfg
|
|
50
|
+
.project
|
|
51
|
+
.pydevproject
|
|
52
|
+
|
|
53
|
+
# Rope
|
|
54
|
+
.ropeproject
|
|
55
|
+
|
|
56
|
+
# Django stuff:
|
|
57
|
+
*.log
|
|
58
|
+
*.pot
|
|
59
|
+
|
|
60
|
+
.DS_Store
|
|
61
|
+
|
|
62
|
+
# Sphinx documentation
|
|
63
|
+
docs/_build/
|
|
64
|
+
|
|
65
|
+
# PyCharm
|
|
66
|
+
.idea/
|
|
67
|
+
|
|
68
|
+
# VSCode
|
|
69
|
+
.vscode/
|
|
70
|
+
|
|
71
|
+
# Pyenv
|
|
72
|
+
.python-version
|
|
73
|
+
|
|
74
|
+
.direnv/
|
redbear-0.1.0/Cargo.lock
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "autocfg"
|
|
7
|
+
version = "1.2.0"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
|
10
|
+
|
|
11
|
+
[[package]]
|
|
12
|
+
name = "heck"
|
|
13
|
+
version = "0.5.0"
|
|
14
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
16
|
+
|
|
17
|
+
[[package]]
|
|
18
|
+
name = "indoc"
|
|
19
|
+
version = "2.0.5"
|
|
20
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
21
|
+
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
|
|
22
|
+
|
|
23
|
+
[[package]]
|
|
24
|
+
name = "libc"
|
|
25
|
+
version = "0.2.153"
|
|
26
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
27
|
+
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
|
28
|
+
|
|
29
|
+
[[package]]
|
|
30
|
+
name = "memoffset"
|
|
31
|
+
version = "0.9.1"
|
|
32
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
33
|
+
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
|
34
|
+
dependencies = [
|
|
35
|
+
"autocfg",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[[package]]
|
|
39
|
+
name = "once_cell"
|
|
40
|
+
version = "1.21.3"
|
|
41
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
42
|
+
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
|
43
|
+
|
|
44
|
+
[[package]]
|
|
45
|
+
name = "portable-atomic"
|
|
46
|
+
version = "1.6.0"
|
|
47
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
48
|
+
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
|
49
|
+
|
|
50
|
+
[[package]]
|
|
51
|
+
name = "proc-macro2"
|
|
52
|
+
version = "1.0.106"
|
|
53
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
54
|
+
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
55
|
+
dependencies = [
|
|
56
|
+
"unicode-ident",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[[package]]
|
|
60
|
+
name = "pyo3"
|
|
61
|
+
version = "0.27.2"
|
|
62
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
63
|
+
checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d"
|
|
64
|
+
dependencies = [
|
|
65
|
+
"indoc",
|
|
66
|
+
"libc",
|
|
67
|
+
"memoffset",
|
|
68
|
+
"once_cell",
|
|
69
|
+
"portable-atomic",
|
|
70
|
+
"pyo3-build-config",
|
|
71
|
+
"pyo3-ffi",
|
|
72
|
+
"pyo3-macros",
|
|
73
|
+
"unindent",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
[[package]]
|
|
77
|
+
name = "pyo3-build-config"
|
|
78
|
+
version = "0.27.2"
|
|
79
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
80
|
+
checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6"
|
|
81
|
+
dependencies = [
|
|
82
|
+
"target-lexicon",
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
[[package]]
|
|
86
|
+
name = "pyo3-ffi"
|
|
87
|
+
version = "0.27.2"
|
|
88
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
89
|
+
checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089"
|
|
90
|
+
dependencies = [
|
|
91
|
+
"libc",
|
|
92
|
+
"pyo3-build-config",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
[[package]]
|
|
96
|
+
name = "pyo3-macros"
|
|
97
|
+
version = "0.27.2"
|
|
98
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
99
|
+
checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02"
|
|
100
|
+
dependencies = [
|
|
101
|
+
"proc-macro2",
|
|
102
|
+
"pyo3-macros-backend",
|
|
103
|
+
"quote",
|
|
104
|
+
"syn",
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
[[package]]
|
|
108
|
+
name = "pyo3-macros-backend"
|
|
109
|
+
version = "0.27.2"
|
|
110
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
111
|
+
checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9"
|
|
112
|
+
dependencies = [
|
|
113
|
+
"heck",
|
|
114
|
+
"proc-macro2",
|
|
115
|
+
"pyo3-build-config",
|
|
116
|
+
"quote",
|
|
117
|
+
"syn",
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
[[package]]
|
|
121
|
+
name = "quote"
|
|
122
|
+
version = "1.0.35"
|
|
123
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
124
|
+
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
|
125
|
+
dependencies = [
|
|
126
|
+
"proc-macro2",
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
[[package]]
|
|
130
|
+
name = "redbear"
|
|
131
|
+
version = "0.1.0"
|
|
132
|
+
dependencies = [
|
|
133
|
+
"pyo3",
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
[[package]]
|
|
137
|
+
name = "syn"
|
|
138
|
+
version = "2.0.114"
|
|
139
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
140
|
+
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
|
|
141
|
+
dependencies = [
|
|
142
|
+
"proc-macro2",
|
|
143
|
+
"quote",
|
|
144
|
+
"unicode-ident",
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
[[package]]
|
|
148
|
+
name = "target-lexicon"
|
|
149
|
+
version = "0.13.4"
|
|
150
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
151
|
+
checksum = "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba"
|
|
152
|
+
|
|
153
|
+
[[package]]
|
|
154
|
+
name = "unicode-ident"
|
|
155
|
+
version = "1.0.12"
|
|
156
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
157
|
+
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
|
158
|
+
|
|
159
|
+
[[package]]
|
|
160
|
+
name = "unindent"
|
|
161
|
+
version = "0.2.3"
|
|
162
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
163
|
+
checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
|
redbear-0.1.0/Cargo.toml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "redbear"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
|
|
7
|
+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
8
|
+
[lib]
|
|
9
|
+
name = "redbear"
|
|
10
|
+
crate-type = ["cdylib"]
|
|
11
|
+
|
|
12
|
+
[dependencies]
|
|
13
|
+
pyo3 = "0.27.2"
|
redbear-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: redbear
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Programming Language :: Rust
|
|
5
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
|
+
Requires-Dist: polars ; extra == 'dev'
|
|
8
|
+
Requires-Dist: pandas ; extra == 'dev'
|
|
9
|
+
Requires-Dist: numpy ; extra == 'dev'
|
|
10
|
+
Requires-Dist: blackbear ; extra == 'dev'
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Python: >=3.11
|
redbear-0.1.0/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Redbear
|
|
2
|
+
|
|
3
|
+
A high-performance Python extension for fast element-wise dictionary operations. Redbear provides a minimal, purpose-built `RedDict` class that delivers significant performance improvements over traditional data science libraries for specific use cases involving numeric dictionaries.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Redbear is inspired by [blackbear](https://github.com/cgdeboer/blackbear) and builds on the concepts introduced there. By moving the implementation to Rust while keeping things as simple as possible, Redbear achieves far better performance across the board.
|
|
8
|
+
|
|
9
|
+
The library is designed for scenarios where:
|
|
10
|
+
- You work with numeric dictionaries (string keys, float values)
|
|
11
|
+
- You need fast element-wise operations (add, subtract, multiply)
|
|
12
|
+
- Performance matters more than generality
|
|
13
|
+
|
|
14
|
+
After heavy optimizations using PyO3 and Arc-based internal sharing, Redbear achieves excellent performance while hiding all the complexity from the library users.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
maturin develop
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import redbear as rb
|
|
26
|
+
|
|
27
|
+
# Create a RedDict from a regular Python dict
|
|
28
|
+
data = {"a": 1.0, "b": 2.0, "c": 3.0}
|
|
29
|
+
rd = rb.RedDict(data)
|
|
30
|
+
|
|
31
|
+
# Scalar operations (creates a new RedDict)
|
|
32
|
+
rd_plus_5 = rd.add_scalar(5.0) # {"a": 6.0, "b": 7.0, "c": 8.0}
|
|
33
|
+
rd_minus_2 = rd.subtract_scalar(2.0) # {"a": -1.0, "b": 0.0, "c": 1.0}
|
|
34
|
+
|
|
35
|
+
# Element-wise operations between two RedDicts
|
|
36
|
+
other = rb.RedDict({"a": 10.0, "b": 20.0, "c": 30.0})
|
|
37
|
+
result = rd.add(other) # {"a": 11.0, "b": 22.0, "c": 33.0}
|
|
38
|
+
result = rd.subtract(other) # {"a": -9.0, "b": -18.0, "c": -27.0}
|
|
39
|
+
result = rd.multiply(other) # {"a": 10.0, "b": 40.0, "c": 90.0}
|
|
40
|
+
|
|
41
|
+
# Get the underlying dict back
|
|
42
|
+
plain_dict = rd.value # {"a": 1.0, "b": 2.0, "c": 3.0}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Benchmarks
|
|
46
|
+
|
|
47
|
+
Run benchmarks with:
|
|
48
|
+
```bash
|
|
49
|
+
pip install -e ".[dev]"
|
|
50
|
+
python -m benchmarks.redbear_way
|
|
51
|
+
python -m benchmarks.numpy_way
|
|
52
|
+
python -m benchmarks.blackbear_way
|
|
53
|
+
python -m benchmarks.polars_way
|
|
54
|
+
python -m benchmarks.pandas_way
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Best Case (keys identical)
|
|
58
|
+
|
|
59
|
+
| Library | Operations | Collection Size | Time (seconds) |
|
|
60
|
+
|---------|------------|-----------------|----------------|
|
|
61
|
+
| Redbear | 100000 x 5 | 10 | 0.056 |
|
|
62
|
+
| Redbear | 1000000 x 5 | 10 | 0.583 |
|
|
63
|
+
| Redbear | 10000 x 5 | 1000 | 0.015 |
|
|
64
|
+
| Redbear | 100000 x 5 | 1000 | 0.145 |
|
|
65
|
+
| Numpy | 100000 x 5 | 10 | 0.285 |
|
|
66
|
+
| Numpy | 1000000 x 5 | 10 | 2.436 |
|
|
67
|
+
| Numpy | 10000 x 5 | 1000 | 0.039 |
|
|
68
|
+
| Numpy | 100000 x 5 | 1000 | 0.371 |
|
|
69
|
+
| Blackbear | 100000 x 5 | 10 | 0.371 |
|
|
70
|
+
| Blackbear | 1000000 x 5 | 10 | 3.755 |
|
|
71
|
+
| Blackbear | 10000 x 5 | 1000 | 3.643 |
|
|
72
|
+
| Blackbear | 100000 x 5 | 1000 | 36.307 |
|
|
73
|
+
| Polars | 100000 x 5 | 10 | 1.072 |
|
|
74
|
+
| Polars | 1000000 x 5 | 10 | 11.147 |
|
|
75
|
+
| Polars | 10000 x 5 | 1000 | 0.132 |
|
|
76
|
+
| Polars | 100000 x 5 | 1000 | 1.219 |
|
|
77
|
+
| Pandas | 100000 x 5 | 10 | 13.466 |
|
|
78
|
+
| Pandas | 1000000 x 5 | 10 | 130.837 |
|
|
79
|
+
| Pandas | 10000 x 5 | 1000 | 1.339 |
|
|
80
|
+
| Pandas | 100000 x 5 | 1000 | 13.432 |
|
|
81
|
+
|
|
82
|
+
### Worst Case (different key order)
|
|
83
|
+
|
|
84
|
+
| Library | Operations | Collection Size | Time (seconds) |
|
|
85
|
+
|---------|------------|-----------------|----------------|
|
|
86
|
+
| Redbear | 100000 x 5 | 10 | 0.561 |
|
|
87
|
+
| Redbear | 1000000 x 5 | 10 | 5.432 |
|
|
88
|
+
| Redbear | 10000 x 5 | 1000 | 0.283 |
|
|
89
|
+
| Redbear | 100000 x 5 | 1000 | 2.842 |
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import blackbear as bb
|
|
2
|
+
import uuid
|
|
3
|
+
import random
|
|
4
|
+
from time import perf_counter
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def run(dict_size, ops_count):
|
|
8
|
+
data = {str(uuid.uuid4()): random.randrange(100000) for _ in range(1, dict_size)}
|
|
9
|
+
|
|
10
|
+
time_start = perf_counter()
|
|
11
|
+
for _ in range(1, ops_count):
|
|
12
|
+
x = bb.add_scalar(data, 4)
|
|
13
|
+
x = bb.add(x, data)
|
|
14
|
+
x = bb.subtract_scalar(x, 1)
|
|
15
|
+
x = bb.subtract(x, data)
|
|
16
|
+
x = bb.multiply_scalar(x, 2)
|
|
17
|
+
time_duration = perf_counter() - time_start
|
|
18
|
+
|
|
19
|
+
print(f"| Blackbear | {ops_count} x 5 | {dict_size} | {time_duration:.3f} |")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if __name__ == "__main__":
|
|
23
|
+
run(10, 100000)
|
|
24
|
+
run(10, 1000000)
|
|
25
|
+
run(1000, 10000)
|
|
26
|
+
run(1000, 100000)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import uuid
|
|
3
|
+
import random
|
|
4
|
+
from time import perf_counter
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def run(dict_size, ops_count):
|
|
8
|
+
data = {str(uuid.uuid4()): random.randrange(100000) for _ in range(0, dict_size)}
|
|
9
|
+
|
|
10
|
+
time_start = perf_counter()
|
|
11
|
+
array = np.fromiter(data.values(), dtype=int, count=len(data))
|
|
12
|
+
for _ in range(0, ops_count):
|
|
13
|
+
x = np.add(array, 4)
|
|
14
|
+
x = np.add(x, array)
|
|
15
|
+
x = np.subtract(array, 1)
|
|
16
|
+
x = np.subtract(x, array)
|
|
17
|
+
x = np.multiply(x, array)
|
|
18
|
+
time_duration = perf_counter() - time_start
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
print(f"| Numpy | {ops_count} x 5 | {dict_size} | {time_duration:.3f} |")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
run(10, 100000)
|
|
26
|
+
run(10, 1000000)
|
|
27
|
+
run(1000, 10000)
|
|
28
|
+
run(1000, 100000)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import uuid
|
|
3
|
+
import random
|
|
4
|
+
from time import perf_counter
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def run(dict_size, ops_count):
|
|
8
|
+
data = {str(uuid.uuid4()): random.randrange(100000) for _ in range(0, dict_size)}
|
|
9
|
+
|
|
10
|
+
time_start = perf_counter()
|
|
11
|
+
df = pd.Series(data, index=data.keys())
|
|
12
|
+
for _ in range(0, ops_count):
|
|
13
|
+
x = df.add(4)
|
|
14
|
+
x = df.add(x)
|
|
15
|
+
x = df.subtract(1)
|
|
16
|
+
x = df.subtract(x)
|
|
17
|
+
x = df.multiply(x)
|
|
18
|
+
time_duration = perf_counter() - time_start
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
print(f"| Pandas | {ops_count} x 5 | {dict_size} | {time_duration:.3f} |")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
run(10, 100000)
|
|
26
|
+
run(10, 1000000)
|
|
27
|
+
run(1000, 10000)
|
|
28
|
+
run(1000, 100000)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import polars as pl
|
|
2
|
+
import uuid
|
|
3
|
+
import random
|
|
4
|
+
from time import perf_counter
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def run(dict_size, ops_count):
|
|
8
|
+
data = {str(uuid.uuid4()): random.randrange(100000) for _ in range(0, dict_size)}
|
|
9
|
+
|
|
10
|
+
time_start = perf_counter()
|
|
11
|
+
series = pl.Series(data.values())
|
|
12
|
+
for _ in range(0, ops_count):
|
|
13
|
+
x = series + 4
|
|
14
|
+
x = x + series
|
|
15
|
+
x = x - 1
|
|
16
|
+
x = x - series
|
|
17
|
+
x = x * series
|
|
18
|
+
time_duration = perf_counter() - time_start
|
|
19
|
+
|
|
20
|
+
print(f"| Polars | {ops_count} x 5 | {dict_size} | {time_duration:.3f} |")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
run(10, 100000)
|
|
25
|
+
run(10, 1000000)
|
|
26
|
+
run(1000, 10000)
|
|
27
|
+
run(1000, 100000)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import redbear as rb
|
|
2
|
+
import uuid
|
|
3
|
+
import random
|
|
4
|
+
from time import perf_counter
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def run(dict_size, ops_count):
|
|
8
|
+
data = {str(uuid.uuid4()): random.randrange(100000) for _ in range(1, dict_size)}
|
|
9
|
+
|
|
10
|
+
time_start = perf_counter()
|
|
11
|
+
d = rb.RedDict(data)
|
|
12
|
+
for _ in range(1, ops_count):
|
|
13
|
+
x = d.add_scalar(4)
|
|
14
|
+
x = x.add(d)
|
|
15
|
+
x = x.subtract_scalar(4)
|
|
16
|
+
x = x.subtract(d)
|
|
17
|
+
x = x.multiply(d)
|
|
18
|
+
time_duration = perf_counter() - time_start
|
|
19
|
+
|
|
20
|
+
print(f"| Redbear | {ops_count} x 5 | {dict_size} | {time_duration:.3f} |")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
run(10, 100000)
|
|
25
|
+
run(10, 1000000)
|
|
26
|
+
run(1000, 10000)
|
|
27
|
+
# This runs for a very long time so it's good to leave it out.
|
|
28
|
+
run(1000, 100000)
|