Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@NotsoanoNimus
Copy link
Contributor

Adding zip and zipWith functional-style macros to the std::core::array module. Take a look at the unit tests and documentation provided to understand how these are working.

Also added a builtin slice cloning function (and a passthrough variant for the temp allocator).

My original use-case for these was to quickly allow the application and assignment of simple operators between slices, a la:

self.state[:self.offset] ^= self.buf[^self.offset..];

This can now be achieved with:

array::zip_with_into(self.state[:self.offset], self.buf[^self.offset..], fn char (char a, char b) => a ^ b);

And inlining these operations with user-defined types that have @operator overloads will be nice to have.


Plain zip variants:

fn void zip() => @pool()
{
	char[] left = "abcde";
	long[] right = { -1, 0x8000, 0 };

	Pair{char, long}[] expected = { {'a', -1}, {'b', 0x8000}, {'c', 0} };

	Pair{char, long}[] zipped = array::tzip(left, right);

	assert(zipped.len == 3);
	foreach (i, c : zipped) assert(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
}

zipWith variants:

fn void zip_with_longest_fill_pointers() => @pool()
{
	ZString field = "0123456789abcdefghijklmnopqrstuvwxyz-_=!";

	char*[] left = { &field[3], &field[1] };
	char[] right = { 0x05, 0x04, 0x0A, 0x10, 0x11 };

	char[] expected = "85agh";

	char[] zipped = array::tzip_with_longest(left, right, fn char (char* a, char b) => a[b], &field[0]);

	assert(zipped.len == 5);
	foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
}

zipWithInto, no allocations necessary:

fn void zip_with_into()
{
	char[] left = { '1', '2', '3', '4' };
	String[6] right = { "one", "two", "three", "four", "five", "six" };

	char[] expected = { '4', '5', '8', '8' };

	array::zip_with_into(left, right, fn char (char a, String b) => a + (char)b.len);

	assert(left.len == 4);
	foreach (i, c : left) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
}

@lerno
Copy link
Collaborator

lerno commented Aug 6, 2025

Can you add something about this in the releasenotes?

@lerno
Copy link
Collaborator

lerno commented Aug 14, 2025

Can we change zip to:

macro zip(Allocator allocator, left, right, bool extend = false, fill_with = EMPTY_MACRO_SLOT) @nodiscard
{ ... }

Because then we get:

Pair{String, long}[] zipped = array::tzip(left, right, "aaa", extend: true);
...
(void)array::tzip(left, right, extend: true, fill_with: (TestStructZip){100, 200}));

This would reduce the number of macros and to me it feels a little more succinct, especially since "zip_longest" isn't a super clear name, and it would reduce it to zip, zip with, zip into.

Possibly we could even do:

macro zip(Allocator allocator, left, right, func = EMPTY_MACRO_SLOT, bool extend = false, fill_with = EMPTY_MACRO_SLOT) @nodiscard

So there's just zip and zip_into

@NotsoanoNimus
Copy link
Contributor Author

NotsoanoNimus commented Aug 15, 2025

Thanks for bringing my attention to this. I will address consolidating the code some more this morning.

Looking at it again after some time has passed (with fresh 👀), I agree that pulling zip_longest pretty much verbatim from our friend Python is just increasing code complexity in array:: while also being very redundant. I will get rid of the _longest items.

However, I think zip_with should remain separate, because its return type is also distinct. Rather than returning a Pair array, it returns a consolidated array from the application of the given function pointer across each element in the inputs. And that returned slice type can be typed as either the left or right operand is.

Edit: Naww, allow me to vacillate on this again and say, yeah, if the user is passing a function pointer or lambda, they know what to expect as a return result. We are now down to just @zip and @zip_into after my most recent push (e1ee586).

@lerno lerno merged commit 702b63d into c3lang:master Aug 16, 2025
37 of 43 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants