From 9ed545ae37dfd1db9758d724e5d10bae5cc00f04 Mon Sep 17 00:00:00 2001 From: Sam Atman Date: Tue, 29 Apr 2025 13:48:34 -0400 Subject: Add result.toOwned() to Normalize.zig Closes #29 The README is also updated to reflect this change. --- README.md | 15 +++++++++++++-- src/Normalize.zig | 9 +++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5d2318e..1069eef 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ zg provides Unicode text processing for Zig projects. ## Unicode Version -The Unicode version supported by zg is 15.1.0. +The Unicode version supported by zg is `15.1.0`. ## Zig Version -The minimum Zig version required is 0.14 dev. +The minimum Zig version required is `0.14`. ## Integrating zg into your Zig Project @@ -325,6 +325,17 @@ test "Normalization" { try expect(try n.eql(allocator, "foϓ", "fo\u{03D2}\u{0301}")); } ``` +The `Result` returned by normalization functions may or may not be copied from the +inputs given. For example, an all-ASCII input does not need to be a copy, and will +be a view of the original slice. Calling `result.deinit(allocator)` will only free +an allocated `Result`, not one which is a view. Thus it is safe to do +unconditionally. + +This does mean that the validity of a `Result` can depend on the original string +staying in memory. To ensure that your `Result` is always a copy, you may call +`try result.toOwned(allocator)`, which will only make a copy if one was not +already made. + ## Caseless Matching via Case Folding diff --git a/src/Normalize.zig b/src/Normalize.zig index 7b87406..97c2649 100644 --- a/src/Normalize.zig +++ b/src/Normalize.zig @@ -220,10 +220,19 @@ test "decompose" { } /// Returned from various functions in this namespace. Remember to call `deinit` to free any allocated memory. +/// Note that normalization functions will not copy what they're given if no normalization is needed, if you +/// need to ensure that this Result outlasts the given string, call `try result.toOwned(allocator)`. This +/// will not make a third copy if the Result is already copied from the input. pub const Result = struct { allocated: bool = false, slice: []const u8, + /// Ensures that the slice result is a copy of the input, by making a copy if it was not. + pub fn toOwned(result: Result, allocator: mem.Allocator) error{OutOfMemory}!Result { + if (result.allocatod) return result; + return .{ .allocated = true, .slice = try allocator.dupe(u8, result.slice) }; + } + pub fn deinit(self: *const Result, allocator: mem.Allocator) void { if (self.allocated) allocator.free(self.slice); } -- cgit v1.2.3