From 34ea2e3eb0f788c01e139499e9ddb1bd246aab37 Mon Sep 17 00:00:00 2001 From: dipinhora Date: Mon, 13 Nov 2017 23:51:11 -0500 Subject: [PATCH] Add `chop` function for chopping `iso` Strings and Arrays This commit adds a `chop` function to both String and Array that works on an `iso` and chops it in two with the left half being a new `iso` String/Array reusing the same pointer and the right half being a `trim_in_place` version of the original String/Array. Both are returned as `iso` and mutable and do not share any memory. The operation does not allocate a new pointer nor copy elements allowing for efficiency. --- packages/builtin/array.pony | 26 ++++++++++++++++ packages/builtin/string.pony | 26 ++++++++++++++++ packages/builtin_test/_test.pony | 52 ++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/packages/builtin/array.pony b/packages/builtin/array.pony index 20ffae098d..3d9ebc93a1 100644 --- a/packages/builtin/array.pony +++ b/packages/builtin/array.pony @@ -208,6 +208,32 @@ class Array[A] is Seq[A] end end + fun iso chop(split_point: USize): (Array[A] iso^, Array[A] iso^) => + """ + Chops the array in half at the split point requested and returns both + the left and right portions. The original array is trimmed in place and + returned as the right portion. If the split point is larger than the + array, the left portion is the original array and the right portion + is a new empty array. + Both arrays are isolated and mutable, as they do not share memory. + The operation does not allocate a new array pointer nor copy elements. + """ + let start_ptr = _ptr + let size' = _size.min(split_point) + let alloc = if size' == _size then _alloc else split_point end + + trim_in_place(split_point) + + let left = recover + if size' > 0 then + from_cpointer(start_ptr._unsafe(), size', alloc) + else + create() + end + end + + (consume left, consume this) + fun copy_to( dst: Array[this->A!], src_idx: USize, diff --git a/packages/builtin/string.pony b/packages/builtin/string.pony index 37fd45a725..e6b4606410 100644 --- a/packages/builtin/string.pony +++ b/packages/builtin/string.pony @@ -377,6 +377,32 @@ actor Main end end + fun iso chop(split_point: USize): (String iso^, String iso^) => + """ + Chops the string in half at the split point requested and returns both + the left and right portions. The original string is trimmed in place and + returned as the right portion. If the split point is larger than the + string, the left portion is the original string and the right portion + is a new empty string. + Both strings are isolated and mutable, as they do not share memory. + The operation does not allocate a new string pointer nor copy elements. + """ + let start_ptr = _ptr + let size' = _size.min(split_point) + let alloc = if size' == _size then _alloc else split_point end + + trim_in_place(split_point) + + let left = recover + if size' > 0 then + from_cpointer(start_ptr._unsafe(), size', alloc) + else + create() + end + end + + (consume left, consume this) + fun is_null_terminated(): Bool => """ Return true if the string is null-terminated and safe to pass to an FFI diff --git a/packages/builtin_test/_test.pony b/packages/builtin_test/_test.pony index 38e4442a6f..b19e583016 100644 --- a/packages/builtin_test/_test.pony +++ b/packages/builtin_test/_test.pony @@ -49,6 +49,7 @@ actor Main is TestList test(_TestStringSpace) test(_TestStringRecalc) test(_TestStringTruncate) + test(_TestStringChop) test(_TestSpecialValuesF32) test(_TestSpecialValuesF64) test(_TestArrayAppend) @@ -61,6 +62,7 @@ actor Main is TestList test(_TestArrayValuesRewind) test(_TestArrayFind) test(_TestArraySwapElements) + test(_TestArrayChop) test(_TestMath128) test(_TestDivMod) test(_TestAddc) @@ -1024,6 +1026,32 @@ class iso _TestStringTruncate is UnitTest h.assert_eq[USize](s.size(), 3) h.assert_eq[USize](s.space(), 31) +class iso _TestStringChop is UnitTest + """ + Test chopping an array + """ + fun name(): String => "builtin/String.chop" + + fun apply(h: TestHelper) => + case(h, "0123", "456", "0123456".clone(), 4) + case(h, "012345", "6", "0123456".clone(), 6) + case(h, "0", "123456", "0123456".clone(), 1) + case(h, "0123456", "", "0123456".clone(), 7) + case(h, "", "0123456", "0123456".clone(), 0) + case(h, "0123", "456", "0123456789".clone().chop(7)._1, 4) + case(h, "0123456", "", "0123456".clone(), 10) + + fun case( + h: TestHelper, + expected_left: String, + expected_right: String, + orig: String iso, + split_point: USize) + => + (let left: String iso, let right: String iso) = (consume orig).chop(split_point) + h.assert_eq[String box](expected_left, consume left) + h.assert_eq[String box](expected_right, consume right) + class iso _TestArrayAppend is UnitTest fun name(): String => "builtin/Array.append" @@ -1317,6 +1345,30 @@ class iso _TestArraySwapElements is UnitTest [as I32: 1; 2; 3].swap_elements(3, 4)? }) +class iso _TestArrayChop is UnitTest + """ + Test chopping an array + """ + fun name(): String => "builtin/Array.chop" + + fun apply(h: TestHelper) => + case(h, [0; 1; 2; 3], [4; 5; 6], recover [0; 1; 2; 3; 4; 5; 6] end, 4) + case(h, [0; 1; 2; 3; 4; 5], [6], recover [0; 1; 2; 3; 4; 5; 6] end, 6) + case(h, [0], [1; 2; 3; 4; 5; 6], recover [0; 1; 2; 3; 4; 5; 6] end, 1) + case(h, [0; 1; 2; 3; 4; 5; 6], Array[U8], recover [0; 1; 2; 3; 4; 5; 6] end, 7) + case(h, Array[U8], [0; 1; 2; 3; 4; 5; 6], recover [0; 1; 2; 3; 4; 5; 6] end, 0) + case(h, [0; 1; 2; 3; 4; 5; 6], Array[U8], recover [0; 1; 2; 3; 4; 5; 6] end, 10) + + fun case( + h: TestHelper, + expected_left: Array[U8], + expected_right: Array[U8], + orig: Array[U8] iso, + split_point: USize) + => + (let left: Array[U8] iso, let right: Array[U8] iso) = (consume orig).chop(split_point) + h.assert_array_eq[U8](expected_left, consume left) + h.assert_array_eq[U8](expected_right, consume right) class iso _TestMath128 is UnitTest """