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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 105b8b3aa2535a774ea28bfe187f56c9d4fe228c0636c153725387bb2a849802
4
- data.tar.gz: 94188aed5c30aeba1e5ad85857f78650801465851e528b9a8163c8e7cd25f40a
3
+ metadata.gz: b1863511a34dcabaa7da8cb19b974f943e8e9609c01a5b43369bae27ed2685e6
4
+ data.tar.gz: eb82ce2fab5f85083e156143cbd27f8bff2df10bc532d107dbc7a30de0d3a989
5
5
  SHA512:
6
- metadata.gz: 85a96f139a5b40dded9a0ce7f3fc6dde6b9837942b5f227bd9d514c74ed716074cefa972a630258e10360ac126e4ddd825d1c4a7d637b1b63f86e6d57c8afa18
7
- data.tar.gz: 02fd7de18bda4350168de5ee2f39af423c39ace7247e9a0ba40c8e948ad52e42c4e6b1a04c6be772559a570a9b0172bd8e3589701e5302c9395e1474c95ce9b2
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 (freezes the backing automatically)
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, `RTYPEDDATA_GET_DATA` for fast struct access (skipping type checks), and `FL_SET_RAW` for freeze (bypassing method dispatch).
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
 
@@ -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")