Skip to content

Commit 9c10c1a

Browse files
xenuStephanTLavavejCaseyCarter
authored
<filesystem>: Preallocate memory in path::operator/ (#4136)
Co-authored-by: Stephan T. Lavavej <[email protected]> Co-authored-by: Casey Carter <[email protected]>
1 parent 46402aa commit 9c10c1a

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

Diff for: stl/inc/filesystem

+29
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,35 @@ namespace filesystem {
13771377
#endif // ^^^ !_HAS_CXX20 ^^^
13781378

13791379
_NODISCARD_FRIEND path operator/(const path& _Left, const path& _Right) { // append a pair of paths together
1380+
const auto _Right_size = _Right._Text.size();
1381+
const auto _Right_first = _Right._Text.data();
1382+
const auto _Right_last = _Right_first + _Right_size;
1383+
1384+
// Handle the most common case: !has_root_name(_Right) && !has_root_directory(_Right)
1385+
if (_Right_size != 0 && !_Has_drive_letter_prefix(_Right_first, _Right_last) && !_Is_slash(*_Right_first)) {
1386+
const auto _Left_size = _Left._Text.size();
1387+
const auto _Left_first = _Left._Text.data();
1388+
const auto _Left_last = _Left_first + _Left_size;
1389+
1390+
// Appending a slash to "X:" would make it an absolute path
1391+
const bool _Left_is_just_drive = _Left_size == 2 && _Is_drive_prefix(_Left_first);
1392+
const bool _Is_slash_needed = _Left_size != 0 && !_Left_is_just_drive && !_Is_slash(_Left_last[-1]);
1393+
1394+
const auto _Total_size = _Left_size + static_cast<size_t>(_Is_slash_needed) + _Right_size;
1395+
1396+
path _Tmp;
1397+
_Tmp._Text._Resize_and_overwrite(_Total_size, [=](wchar_t* _Ptr, const size_t _Size) {
1398+
_CSTD memcpy(_Ptr, _Left_first, _Left_size * sizeof(wchar_t));
1399+
_Ptr += _Left_size;
1400+
if (_Is_slash_needed) {
1401+
*_Ptr++ = preferred_separator;
1402+
}
1403+
_CSTD memcpy(_Ptr, _Right_first, _Right_size * sizeof(wchar_t));
1404+
return _Size;
1405+
});
1406+
return _Tmp;
1407+
}
1408+
13801409
path _Tmp = _Left;
13811410
_Tmp /= _Right;
13821411
return _Tmp;

Diff for: tests/std/tests/P0218R1_filesystem/test.cpp

+17-5
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ struct slash_test_case {
544544
};
545545

546546
constexpr slash_test_case slashTestCases[] = {
547+
{L""sv, L""sv, L""sv},
547548
{L"relative"sv, L"other"sv, LR"(relative\other)"sv},
548549
{L"//server"sv, L"share"sv, LR"(//server\share)"sv},
549550
{L"//server/"sv, L"share"sv, LR"(//server/share)"sv},
@@ -555,6 +556,7 @@ constexpr slash_test_case slashTestCases[] = {
555556
{L""sv, L"cat"sv, L"cat"sv},
556557
{L"./"sv, L"cat"sv, L"./cat"sv}, // original test case catching a bug in the above
557558
{L"c:"sv, L""sv, L"c:"sv},
559+
{L"c:"sv, L"dog"sv, L"c:dog"sv},
558560
{L"c:cat"sv, L"/dog"sv, L"c:/dog"sv},
559561
{L"c:/cat"sv, L"/dog"sv, L"c:/dog"sv},
560562
{L"c:cat"sv, L"c:dog"sv, LR"(c:cat\dog)"sv},
@@ -568,13 +570,23 @@ constexpr slash_test_case slashTestCases[] = {
568570
bool run_slash_test_case(const slash_test_case& testCase) {
569571
path p(testCase.a);
570572
p /= testCase.b;
571-
if (p.native() == testCase.expected) {
572-
return true;
573+
574+
if (p.native() != testCase.expected) {
575+
wcerr << L"With operator/=, expected " << testCase.a << L" / " << testCase.b << L" to be " << testCase.expected
576+
<< L" but it was " << p.native() << L"\n";
577+
return false;
573578
}
574579

575-
wcerr << L"Expected " << testCase.a << L" / " << testCase.b << L" to be " << testCase.expected << L" but it was "
576-
<< p.native() << L"\n";
577-
return false;
580+
// Also test operator/, which was optimized by GH-4136.
581+
p = path{testCase.a} / path{testCase.b};
582+
583+
if (p.native() != testCase.expected) {
584+
wcerr << L"With operator/, expected " << testCase.a << L" / " << testCase.b << L" to be " << testCase.expected
585+
<< L" but it was " << p.native() << L"\n";
586+
return false;
587+
}
588+
589+
return true;
578590
}
579591

580592
void test_iterators() {

0 commit comments

Comments
 (0)