string_view 0.1.0 → 0.2.0
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.
- checksums.yaml +4 -4
- data/README.md +25 -4
- data/ext/string_view/extconf.rb +1 -1
- data/ext/string_view/string_view.c +735 -207
- data/ext/string_view/string_view.h +121 -0
- data/ext/string_view/string_view_core_ext.c +44 -0
- data/ext/string_view/string_view_pool.c +204 -0
- data/ext/string_view/string_view_strict.c +102 -0
- data/lib/string_view/core_ext.rb +5 -0
- data/lib/string_view/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b1863511a34dcabaa7da8cb19b974f943e8e9609c01a5b43369bae27ed2685e6
|
|
4
|
+
data.tar.gz: eb82ce2fab5f85083e156143cbd27f8bff2df10bc532d107dbc7a30de0d3a989
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f43e32e7e5fe70e66f1e3eb0431706bbf07506daab0ee157eff68e1b3d61bda1c4144e161a7cf41291f032f5f90696696867854463ba65ac57af215979238eb4
|
|
7
|
+
data.tar.gz: d6598af6460da6cc103e4634ea68b5e412ab8642263ecfb39c24d88c9309f0a3983a1364a600e0e20cdf210d3c63892d7832e78d06795c4e59c97734a8a62676
|
data/README.md
CHANGED
|
@@ -39,6 +39,7 @@ StringView methods are organized into three tiers based on their allocation beha
|
|
|
39
39
|
|
|
40
40
|
### Design decisions
|
|
41
41
|
|
|
42
|
+
- **Backing strings must be frozen.** `StringView.new`, `reset!`, and `Pool.new` all raise `FrozenError` if the string is not already frozen. This guarantees the backing bytes cannot be mutated or reallocated while views point into them. Use `String#view` (via `require "string_view/core_ext"`) if you want automatic freezing.
|
|
42
43
|
- **`to_str` is private.** Ruby's internal coercion protocol (`rb_check_string_type`) ignores method visibility, so StringView works seamlessly with `Regexp#=~`, string interpolation, and `String#+`. But `respond_to?(:to_str)` returns `false`, so code that explicitly checks for string-like objects won't treat StringView as a drop-in String replacement. When coercion happens, it returns a frozen shared string (zero-copy for heap-allocated backings).
|
|
43
44
|
- **All bang methods raise `FrozenError`.** StringView is immutable — `upcase!`, `gsub!`, `slice!`, etc. all raise immediately.
|
|
44
45
|
- **`method_missing` is a safety net.** Any String method not yet implemented natively raises `NotImplementedError` with a message telling you to call `.to_s.method_name(...)` explicitly. No silent fallback.
|
|
@@ -151,7 +152,7 @@ The gem includes a C extension that compiles during installation. It requires Ru
|
|
|
151
152
|
```ruby
|
|
152
153
|
require "string_view"
|
|
153
154
|
|
|
154
|
-
# Create from a String
|
|
155
|
+
# Create from a frozen String
|
|
155
156
|
sv = StringView.new("Hello, world!")
|
|
156
157
|
|
|
157
158
|
# Slicing returns StringView — zero copy
|
|
@@ -179,7 +180,7 @@ sv.split(", ") # => ["Hello", "world!"] (Array of Strings)
|
|
|
179
180
|
|
|
180
181
|
```ruby
|
|
181
182
|
# Simulate a large HTTP response or log chunk
|
|
182
|
-
buffer = File.read("large_file.txt")
|
|
183
|
+
buffer = File.read("large_file.txt").freeze
|
|
183
184
|
sv = StringView.new(buffer)
|
|
184
185
|
|
|
185
186
|
# Extract fields without copying the entire buffer
|
|
@@ -196,12 +197,32 @@ body.match?(/\d{4}-\d{2}-\d{2}/) # Regex on the view
|
|
|
196
197
|
```ruby
|
|
197
198
|
sv = StringView.new("initial content")
|
|
198
199
|
|
|
199
|
-
# Re-point at a different backing string
|
|
200
|
+
# Re-point at a different (frozen) backing string
|
|
200
201
|
new_data = "different content"
|
|
201
202
|
sv.reset!(new_data, 0, new_data.bytesize)
|
|
202
203
|
sv.to_s # => "different content"
|
|
203
204
|
```
|
|
204
205
|
|
|
206
|
+
### `String#view` (core extension)
|
|
207
|
+
|
|
208
|
+
For convenience, you can add a `view` method directly to `String` via an opt-in require:
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
require "string_view/core_ext"
|
|
212
|
+
|
|
213
|
+
buf = "Hello, world! This is a large buffer."
|
|
214
|
+
greeting = buf.view(0, 5) # => StringView "Hello"
|
|
215
|
+
name = buf.view(7, 5) # => StringView "world"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
This includes the `StringView::CoreExt` module into `String`. The `view` method takes a byte offset and byte length, and returns a `StringView` backed by a pool that is lazily created and cached per string. Subsequent `view` calls on the same string reuse the pool, amortizing allocation cost.
|
|
219
|
+
|
|
220
|
+
Calling `view` implicitly freezes the string. This is required because StringView holds a direct pointer into the string's memory — if the string were mutated or resized, all views would be invalidated.
|
|
221
|
+
|
|
222
|
+
The pool cache uses an `ObjectSpace::WeakKeyMap` internally, so pools are automatically cleaned up when the string is garbage collected.
|
|
223
|
+
|
|
224
|
+
This require is opt-in — `require "string_view"` alone never modifies `String`.
|
|
225
|
+
|
|
205
226
|
## Internals
|
|
206
227
|
|
|
207
228
|
### Struct layout
|
|
@@ -230,7 +251,7 @@ For UTF-8 strings with actual multibyte content, StringView uses two techniques:
|
|
|
230
251
|
|
|
231
252
|
### Compilation
|
|
232
253
|
|
|
233
|
-
The extension is compiled with `-O3` and uses `__attribute__((always_inline))` on hot paths
|
|
254
|
+
The extension is compiled with `-O3` and uses `__attribute__((always_inline))` on hot paths and `RTYPEDDATA_GET_DATA` for fast struct access (skipping type checks).
|
|
234
255
|
|
|
235
256
|
## Development
|
|
236
257
|
|
data/ext/string_view/extconf.rb
CHANGED
|
@@ -9,7 +9,7 @@ $CFLAGS << " -std=c99 -O3 -Wall -Wextra -Wno-unused-parameter"
|
|
|
9
9
|
$CXXFLAGS = " -std=c++17 -O3 -DNDEBUG"
|
|
10
10
|
|
|
11
11
|
# Tell mkmf about our source files (C and C++ mixed)
|
|
12
|
-
$srcs = ["string_view.c", "simdutf.cpp"]
|
|
12
|
+
$srcs = ["string_view.c", "string_view_strict.c", "string_view_pool.c", "string_view_core_ext.c", "simdutf.cpp"]
|
|
13
13
|
$INCFLAGS << " -I$(srcdir)"
|
|
14
14
|
|
|
15
15
|
create_makefile("string_view/string_view")
|