{"id":21651830,"url":"https://github.com/hoytech/test-zerocopy","last_synced_at":"2025-03-20T04:06:38.406Z","repository":{"id":16200369,"uuid":"18947129","full_name":"hoytech/Test-ZeroCopy","owner":"hoytech","description":"Test that two strings share the same memory","archived":false,"fork":false,"pushed_at":"2014-10-30T04:26:30.000Z","size":184,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-01-25T05:43:06.891Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hoytech.png","metadata":{"files":{"readme":"README.pod","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-04-19T17:50:51.000Z","updated_at":"2014-09-09T17:56:44.000Z","dependencies_parsed_at":"2022-09-12T16:23:53.285Z","dependency_job_id":null,"html_url":"https://github.com/hoytech/Test-ZeroCopy","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoytech%2FTest-ZeroCopy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoytech%2FTest-ZeroCopy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoytech%2FTest-ZeroCopy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoytech%2FTest-ZeroCopy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hoytech","download_url":"https://codeload.github.com/hoytech/Test-ZeroCopy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244547606,"owners_count":20470103,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-25T07:49:46.633Z","updated_at":"2025-03-20T04:06:38.382Z","avatar_url":"https://github.com/hoytech.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"package Test::ZeroCopy;\n\nuse strict;\n\nour $VERSION = '0.110';\n\nrequire XSLoader;\nXSLoader::load('Test::ZeroCopy', $VERSION);\n\nuse base 'Test::Builder::Module';\nour @EXPORT = qw(is_zerocopy isnt_zerocopy);\n\n\nsub _impl {\n  my $tb = __PACKAGE__-\u003ebuilder;\n\n  my $desc = $_[2] || '';\n  my $want_zerocopy = $_[3];\n\n  my $addr1 = get_pv_address($_[0]);\n  my $addr2 = get_pv_address($_[1]);\n\n  if (!defined $addr1 || !defined $addr2) {\n    $tb-\u003eok(!$want_zerocopy, \"$desc: One or both args aren't strings (don't have SvPV values)\");\n    return;\n  }\n\n  my $len1 = get_pv_cur($_[0]);\n  my $len2 = get_pv_cur($_[1]);\n\n  $tb-\u003ediag(sprintf(\"ZC: %s%lx+%lx vs %lx+%lx\", ($desc ? \"$desc: \" : \"\"), $addr1, $len1, $addr2, $len2));\n\n  if ($addr1 == $addr2 \u0026\u0026 $len1 == $len2) {\n    $tb-\u003eok($want_zerocopy, \"$desc =\u003e (exact overlap)\");\n  } elsif ($addr1 \u003e= $addr2 \u0026\u0026 $addr1 \u003c ($addr2 + $len2)) {\n    $tb-\u003eok($want_zerocopy, \"$desc =\u003e (first starts inside second)\");\n  } elsif ($addr2 \u003e= $addr1 \u0026\u0026 $addr2 \u003c ($addr1 + $len1)) {\n    $tb-\u003eok($want_zerocopy, \"$desc =\u003e (second starts inside first)\");\n  } else {\n    $tb-\u003eok(!$want_zerocopy, \"$desc =\u003e (no overlap)\");\n  }\n}\n\nsub is_zerocopy {\n  $_[3] = 1;\n  goto \u0026_impl;\n}\n\nsub isnt_zerocopy {\n  $_[3] = 0;\n  goto \u0026_impl;\n}\n\n\n1;\n\n\n\n__END__\n\n=encoding utf-8\n\n=head1 NAME\n\nTest::ZeroCopy - Test that two strings share the same memory\n\n=head1 SYNOPSIS\n\n    use Test::ZeroCopy;\n\n    is_zerocopy($str1, $str2);\n    isnt_zerocopy($str3, $str4);\n\n\n=head1 BACKGROUND\n\nIn applications that attempt to handle large strings efficiently, it can often be a huge win to avoid copying strings.\n\nHowever, unless you are super careful, it's easy to write perl code that copies strings without realising it:\n\n    my $str = \"long string goes here\";\n\n    sub getstring {\n      my $arg = shift; # this is a copy\n      return $arg;\n    }\n\n    my $ret = getstring($str); # this is another copy\n\nOne solution is to pass references to the string around. Another is to use L\u003cData::Alias\u003e.\n\nUnfortunately, neither of these approaches help when you want to take a substring of the large string: C\u003csubstr\u003e always copies the contents of the string. In C we could avoid copying and instead pass around pointers that point into the string.\n\nAlthough perl doesn't directly support pointers, it is still possible to take a zero-copy substring by creating a scalar with a C\u003cSvPV\u003e pointing into the large string and a C\u003cSvLEN\u003e set to 0 to indicate that the memory is \"owned\" by the large string. Also, the reference counts of the two strings are linked so that the large buffer will only be reclaimed once all substrings go out of scope.\n\nL\u003cString::Slice\u003e is an example of a module that can create zero-copy sub-strings or \"slices\" in this way.\n\nThis module came about because I got tired of sprinkling L\u003cDevel::Peek\u003e C\u003cDump\u003e statements around my code to confirm no copying occurred. Here is an example of how to do that:\n\n    use String::Slice;\n    use Devel::Peek;\n\n    my $buf = \"ABCDEF\";\n    my $slice = \"\";\n    slice($slice, $buf, 1, 3);\n\n    Dump($buf);\n    Dump($slice);\n\nAnd the (abridged) output:\n\n    SV = PV(0x14e0c20) at 0x1501270\n      PV = 0x14fa1f0 \"ABCDEF\"\\0\n      CUR = 6\n      LEN = 16\n    SV = PVMG(0x1528db0) at 0x150d678\n      PV = 0x14fa1f1 \"BCD\"\n      CUR = 3\n      LEN = 0\n\nNotice how the PV values point into the same buffer.\n\nInstead of manual inspection, this module lets you add these assertions to your test-suites to ensure that you (or future maintainers) don't accidentally add wasteful copy operations.\n\n\n\n=head1 USAGE\n\nThis module provides two L\u003cTest::More\u003e-compatible testing functions: C\u003cis_zerocopy\u003e and C\u003cisnt_zerocopy\u003e.\n\nEach of these functions should be passed two strings. C\u003cis_zerocopy\u003e will assert that the backing memory is shared between the two strings. This is assumed to be the case when any portions of their PV buffers overlap.\n\nThe backing memory is trivially shared in the case where the two strings are the same (ie C\u003cis_zerocopy($str, $str)\u003e), but is much more interesting when one is a substring or \"slice\" of the other and they happen to use the same backing memory (see above).\n\nC\u003cisnt_zerocopy\u003e is the opposite and it will assert that the backing memory is I\u003cnot\u003e shared between the two strings.\n\nYou can also use this module to get the PV address from a perl program (which I couldn't figure out how to do with L\u003cB\u003e):\n\n    require Test::ZeroCopy;\n    my $addr = Test::ZeroCopy::get_pv_address($string);\n\n\n\n\n=head1 SEE ALSO\n\nL\u003cTest-ZeroCopy github repo|https://github.com/hoytech/Test-ZeroCopy\u003e\n\nL\u003cData::Alias\u003e - Sometimes more convenient to use this module than to use references\n\nL\u003cString::Slice\u003e - Simple module that can make zero-copy substrings\n\nL\u003cFile::Map\u003e - Interface to C\u003cmmap()\u003e that lets you \"read in\" a whole file into a string suitable for performing zero-copy substring operations\n\nL\u003cLMDB_File\u003e - In-process database that supports zero-copy reads\n\n\n=head1 AUTHOR\n\nDoug Hoyte, C\u003c\u003c \u003cdoug@hcsw.org\u003e \u003e\u003e\n\n=head1 COPYRIGHT \u0026 LICENSE\n\nCopyright 2014 Doug Hoyte.\n\nThis module is licensed under the same terms as perl itself.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoytech%2Ftest-zerocopy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhoytech%2Ftest-zerocopy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoytech%2Ftest-zerocopy/lists"}