Skip to content

Commit

Permalink
static operator() for stateless functors (#4358)
Browse files Browse the repository at this point in the history
Co-authored-by: Casey Carter <[email protected]>
Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
3 people authored Feb 6, 2024
1 parent 0c47a7c commit 2fa1641
Show file tree
Hide file tree
Showing 27 changed files with 732 additions and 535 deletions.
16 changes: 8 additions & 8 deletions stl/inc/__msvc_bit_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,19 +376,19 @@ constexpr decltype(auto) _Select_countr_zero_impl(_Fn _Callback) {
#if _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20
if (!_STD is_constant_evaluated()) {
#ifdef __AVX2__
return _Callback([](_Ty _Val) { return _Countr_zero_tzcnt(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_tzcnt(_Val); });
#else // ^^^ AVX2 / not AVX2 vvv
const bool _Definitely_have_tzcnt = __isa_available >= _Stl_isa_available_avx2;
if (_Definitely_have_tzcnt) {
return _Callback([](_Ty _Val) { return _Countr_zero_tzcnt(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_tzcnt(_Val); });
} else {
return _Callback([](_Ty _Val) { return _Countr_zero_bsf(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_bsf(_Val); });
}
#endif // ^^^ not AVX2 ^^^
}
#endif // ^^^ _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20 ^^^
// C++17 constexpr gcd() calls this function, so it should be constexpr unless we detect runtime evaluation.
return _Callback([](_Ty _Val) { return _Countr_zero_fallback(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_fallback(_Val); });
}

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
Expand Down Expand Up @@ -420,16 +420,16 @@ _CONSTEXPR20 decltype(auto) _Select_popcount_impl(_Fn _Callback) {
#ifndef __AVX__
const bool _Definitely_have_popcnt = __isa_available >= _Stl_isa_available_sse42;
if (!_Definitely_have_popcnt) {
return _Callback([](_Ty _Val) { return _Popcount_fallback(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Popcount_fallback(_Val); });
}
#endif // !defined(__AVX__)
return _Callback([](_Ty _Val) { return _Unchecked_x86_x64_popcount(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Unchecked_x86_x64_popcount(_Val); });
#elif _HAS_NEON_INTRINSICS // ^^^ x86/x64 intrinsics available / ARM64 intrinsics available vvv
return _Callback([](_Ty _Val) { return _Arm64_popcount(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Arm64_popcount(_Val); });
#endif // ^^^ ARM64 intrinsics available ^^^
}
#endif // ^^^ any intrinsics available ^^^
return _Callback([](_Ty _Val) { return _Popcount_fallback(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Popcount_fallback(_Val); });
}

#undef _HAS_POPCNT_INTRINSICS
Expand Down
8 changes: 4 additions & 4 deletions stl/inc/__msvc_tzdb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,28 +101,28 @@ struct _Tzdb_deleter;

template <>
struct _Tzdb_deleter<__std_tzdb_time_zones_info> {
void operator()(__std_tzdb_time_zones_info* _Info) const noexcept {
_STATIC_CALL_OPERATOR void operator()(__std_tzdb_time_zones_info* _Info) _CONST_CALL_OPERATOR noexcept {
__std_tzdb_delete_time_zones(_Info);
}
};

template <>
struct _Tzdb_deleter<__std_tzdb_current_zone_info> {
void operator()(__std_tzdb_current_zone_info* _Info) const noexcept {
_STATIC_CALL_OPERATOR void operator()(__std_tzdb_current_zone_info* _Info) _CONST_CALL_OPERATOR noexcept {
__std_tzdb_delete_current_zone(_Info);
}
};

template <>
struct _Tzdb_deleter<__std_tzdb_sys_info> {
void operator()(__std_tzdb_sys_info* _Info) const noexcept {
_STATIC_CALL_OPERATOR void operator()(__std_tzdb_sys_info* _Info) _CONST_CALL_OPERATOR noexcept {
__std_tzdb_delete_sys_info(_Info);
}
};

template <>
struct _Tzdb_deleter<__std_tzdb_leap_info[]> {
void operator()(__std_tzdb_leap_info* _Info) const noexcept {
_STATIC_CALL_OPERATOR void operator()(__std_tzdb_leap_info* _Info) _CONST_CALL_OPERATOR noexcept {
__std_tzdb_delete_leap_seconds(_Info);
}
};
Expand Down
618 changes: 357 additions & 261 deletions stl/inc/algorithm

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion stl/inc/bitset
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ struct hash<bitset<_Bits>> {
using _ARGUMENT_TYPE_NAME _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS = bitset<_Bits>;
using _RESULT_TYPE_NAME _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS = size_t;

_NODISCARD size_t operator()(const bitset<_Bits>& _Keyval) const noexcept {
_NODISCARD _STATIC_CALL_OPERATOR size_t operator()(const bitset<_Bits>& _Keyval) _CONST_CALL_OPERATOR noexcept {
return _Hash_representation(_Keyval._Array);
}
};
Expand Down
27 changes: 14 additions & 13 deletions stl/inc/compare
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,8 @@ _EXPORT_STD struct compare_three_way {

struct _Synth_three_way {
template <class _Ty1, class _Ty2>
_NODISCARD constexpr auto operator()(const _Ty1& _Left, const _Ty2& _Right) const
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(
const _Ty1& _Left, const _Ty2& _Right) _CONST_CALL_OPERATOR
requires requires {
{ _Left < _Right } -> _Boolean_testable;
{ _Right < _Left } -> _Boolean_testable;
Expand Down Expand Up @@ -409,8 +410,8 @@ namespace _Strong_order {
public:
template <class _Ty1, class _Ty2>
requires (_Choice<_Ty1&, _Ty2&>._Strategy != _St::_None)
_NODISCARD constexpr strong_ordering operator()(_Ty1&& _Left, _Ty2&& _Right) const
noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
_NODISCARD _STATIC_CALL_OPERATOR constexpr strong_ordering operator()(
_Ty1&& _Left, _Ty2&& _Right) _CONST_CALL_OPERATOR noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
constexpr _St _Strat = _Choice<_Ty1&, _Ty2&>._Strategy;
if constexpr (_Strat == _St::_Adl) {
return static_cast<strong_ordering>(strong_order(_Left, _Right)); // intentional ADL
Expand Down Expand Up @@ -516,8 +517,8 @@ namespace _Weak_order {
public:
template <class _Ty1, class _Ty2>
requires (_Choice<_Ty1&, _Ty2&>._Strategy != _St::_None)
_NODISCARD constexpr weak_ordering operator()(_Ty1&& _Left, _Ty2&& _Right) const
noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
_NODISCARD _STATIC_CALL_OPERATOR constexpr weak_ordering operator()(
_Ty1&& _Left, _Ty2&& _Right) _CONST_CALL_OPERATOR noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
constexpr _St _Strat = _Choice<_Ty1&, _Ty2&>._Strategy;
if constexpr (_Strat == _St::_Adl) {
return static_cast<weak_ordering>(weak_order(_Left, _Right)); // intentional ADL
Expand Down Expand Up @@ -647,8 +648,8 @@ namespace _Partial_order {
public:
template <class _Ty1, class _Ty2>
requires (_Choice<_Ty1&, _Ty2&>._Strategy != _St::_None)
_NODISCARD constexpr partial_ordering operator()(_Ty1&& _Left, _Ty2&& _Right) const
noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
_NODISCARD _STATIC_CALL_OPERATOR constexpr partial_ordering operator()(
_Ty1&& _Left, _Ty2&& _Right) _CONST_CALL_OPERATOR noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
constexpr _St _Strat = _Choice<_Ty1&, _Ty2&>._Strategy;
if constexpr (_Strat == _St::_Adl) {
return static_cast<partial_ordering>(/* ADL */ partial_order(_Left, _Right));
Expand Down Expand Up @@ -709,8 +710,8 @@ namespace _Compare_strong_order_fallback {
public:
template <class _Ty1, class _Ty2>
requires (_Choice<_Ty1&, _Ty2&>._Strategy != _St::_None)
_NODISCARD constexpr strong_ordering operator()(_Ty1&& _Left, _Ty2&& _Right) const
noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
_NODISCARD _STATIC_CALL_OPERATOR constexpr strong_ordering operator()(
_Ty1&& _Left, _Ty2&& _Right) _CONST_CALL_OPERATOR noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
constexpr _St _Strat = _Choice<_Ty1&, _Ty2&>._Strategy;
if constexpr (_Strat == _St::_Strong) {
return _STD strong_order(_Left, _Right);
Expand Down Expand Up @@ -759,8 +760,8 @@ namespace _Compare_weak_order_fallback {
public:
template <class _Ty1, class _Ty2>
requires (_Choice<_Ty1&, _Ty2&>._Strategy != _St::_None)
_NODISCARD constexpr weak_ordering operator()(_Ty1&& _Left, _Ty2&& _Right) const
noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
_NODISCARD _STATIC_CALL_OPERATOR constexpr weak_ordering operator()(
_Ty1&& _Left, _Ty2&& _Right) _CONST_CALL_OPERATOR noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
constexpr _St _Strat = _Choice<_Ty1&, _Ty2&>._Strategy;
if constexpr (_Strat == _St::_Weak) {
return _STD weak_order(_Left, _Right);
Expand Down Expand Up @@ -817,8 +818,8 @@ namespace _Compare_partial_order_fallback {
public:
template <class _Ty1, class _Ty2>
requires (_Choice<_Ty1&, _Ty2&>._Strategy != _St::_None)
_NODISCARD constexpr partial_ordering operator()(_Ty1&& _Left, _Ty2&& _Right) const
noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
_NODISCARD _STATIC_CALL_OPERATOR constexpr partial_ordering operator()(
_Ty1&& _Left, _Ty2&& _Right) _CONST_CALL_OPERATOR noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
constexpr _St _Strat = _Choice<_Ty1&, _Ty2&>._Strategy;
if constexpr (_Strat == _St::_Partial) {
return _STD partial_order(_Left, _Right);
Expand Down
12 changes: 6 additions & 6 deletions stl/inc/concepts
Original file line number Diff line number Diff line change
Expand Up @@ -122,26 +122,26 @@ namespace ranges {
struct _Cpo {
template <class _Ty1, class _Ty2>
requires _Use_ADL_swap<_Ty1, _Ty2>
constexpr void operator()(_Ty1&& __t, _Ty2&& __u) const
_STATIC_CALL_OPERATOR constexpr void operator()(_Ty1&& __t, _Ty2&& __u) _CONST_CALL_OPERATOR
noexcept(noexcept(swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)))) { // intentional ADL
swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)); // intentional ADL
}

template <class _Ty>
requires (!_Use_ADL_swap<_Ty&, _Ty&> && move_constructible<_Ty> && assignable_from<_Ty&, _Ty>)
constexpr void operator()(_Ty& __x, _Ty& __y) const
_STATIC_CALL_OPERATOR constexpr void operator()(_Ty& __x, _Ty& __y) _CONST_CALL_OPERATOR
noexcept(is_nothrow_move_constructible_v<_Ty> && is_nothrow_move_assignable_v<_Ty>) {
_Ty __tmp(static_cast<_Ty&&>(__x));
__x = static_cast<_Ty&&>(__y);
__y = static_cast<_Ty&&>(__tmp);
}

template <class _Ty1, class _Ty2, size_t _Size>
constexpr void operator()(_Ty1 (&__t)[_Size], _Ty2 (&__u)[_Size]) const
noexcept(noexcept((*this)(__t[0], __u[0])))
requires requires { (*this)(__t[0], __u[0]); } {
_STATIC_CALL_OPERATOR constexpr void operator()(_Ty1 (&__t)[_Size], _Ty2 (&__u)[_Size]) _CONST_CALL_OPERATOR
noexcept(noexcept(operator()(__t[0], __u[0])))
requires requires(_Cpo __fn) { __fn(__t[0], __u[0]); } {
for (size_t __i = 0; __i < _Size; ++__i) {
(*this)(__t[__i], __u[__i]);
operator()(__t[__i], __u[__i]);
}
}
};
Expand Down
3 changes: 2 additions & 1 deletion stl/inc/coroutine
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ _NODISCARD constexpr bool operator>=(const coroutine_handle<> _Left, const corou

template <class _Promise>
struct hash<coroutine_handle<_Promise>> {
_NODISCARD size_t operator()(const coroutine_handle<_Promise>& _Coro) const noexcept {
_NODISCARD _STATIC_CALL_OPERATOR size_t operator()(
const coroutine_handle<_Promise>& _Coro) _CONST_CALL_OPERATOR noexcept {
return _Hash_representation(_Coro.address());
}
};
Expand Down
53 changes: 37 additions & 16 deletions stl/inc/execution
Original file line number Diff line number Diff line change
Expand Up @@ -3658,7 +3658,8 @@ template <class _Ty>
struct _Casty_plus {
// Adds the two arguments together and casts the result back to _Ty.
// pre: the result from adding the two arguments together can fit in _Ty
_NODISCARD constexpr _Ty operator()(_Ty _Val1, _Ty _Val2) const noexcept /* terminates */ {
_NODISCARD _STATIC_CALL_OPERATOR constexpr _Ty operator()(_Ty _Val1, _Ty _Val2) _CONST_CALL_OPERATOR noexcept
/* terminates */ {
return static_cast<_Ty>(_Val1 + _Val2);
}
};
Expand Down Expand Up @@ -5049,14 +5050,21 @@ _FwdIt2 adjacent_difference(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _Last,
return _Dest;
}

template <class _Ty>
struct _Inplace_destroy_fn {
_STATIC_CALL_OPERATOR void operator()(_Ty& _Obj) _CONST_CALL_OPERATOR noexcept {
_STD _Destroy_in_place(_Obj);
}
};

_EXPORT_STD template <class _ExPo, class _NoThrowFwdIt, _Enable_if_execution_policy_t<_ExPo> /* = 0 */>
void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept /* terminates */ {
// destroy all elements in [_First, _Last)
_REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt);
_STD _Adl_verify_range(_First, _Last);
using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>;
if constexpr (!is_trivially_destructible_v<_Ty>) {
_STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _STD _Destroy_in_place(_Obj); });
_STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, _Inplace_destroy_fn<_Ty>{});
}
}

Expand All @@ -5074,11 +5082,18 @@ _NoThrowFwdIt destroy_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_
_STD advance(_First, _Count);
return _First;
} else {
return _STD for_each_n(
_STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _STD _Destroy_in_place(_Obj); });
return _STD for_each_n(_STD forward<_ExPo>(_Exec), _First, _Count, _Inplace_destroy_fn<_Ty>{});
}
}

template <class _Ty>
struct _Inplace_default_construct_fn {
_STATIC_CALL_OPERATOR void operator()(_Ty& _Obj) _CONST_CALL_OPERATOR
noexcept(is_nothrow_default_constructible_v<_Ty>) {
_STD _Default_construct_in_place(_Obj);
}
};

_EXPORT_STD template <class _ExPo, class _NoThrowFwdIt, _Enable_if_execution_policy_t<_ExPo> /* = 0 */>
void uninitialized_default_construct(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept
/* terminates */ {
Expand All @@ -5087,8 +5102,7 @@ void uninitialized_default_construct(_ExPo&& _Exec, const _NoThrowFwdIt _First,
_STD _Adl_verify_range(_First, _Last);
using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>;
if constexpr (!is_trivially_default_constructible_v<_Ty>) {
_STD for_each(
_STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _STD _Default_construct_in_place(_Obj); });
_STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, _Inplace_default_construct_fn<_Ty>{});
}
}

Expand All @@ -5107,11 +5121,18 @@ _NoThrowFwdIt uninitialized_default_construct_n(_ExPo&& _Exec, _NoThrowFwdIt _Fi
_STD advance(_First, _Count);
return _First;
} else {
return _STD for_each_n(
_STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _STD _Default_construct_in_place(_Obj); });
return _STD for_each_n(_STD forward<_ExPo>(_Exec), _First, _Count, _Inplace_default_construct_fn<_Ty>{});
}
}

template <class _Ty>
struct _Inplace_value_construct_fn {
_STATIC_CALL_OPERATOR void operator()(_Ty& _Obj) _CONST_CALL_OPERATOR
noexcept(is_nothrow_default_constructible_v<_Ty>) {
_STD _Construct_in_place(_Obj);
}
};

_EXPORT_STD template <class _ExPo, class _NoThrowFwdIt, _Enable_if_execution_policy_t<_ExPo> /* = 0 */>
void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt _Last) noexcept /* terminates */ {
// value-initialize all elements in [_First, _Last)
Expand All @@ -5128,10 +5149,10 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt
auto _Count = _STD distance(_UFirst, _ULast);
if (_Count >= 2) { // ... with at least 2 elements
_TRY_BEGIN
using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>;
auto _Ctor_fn = [](_Ty& _Obj) { _STD _Construct_in_place(_Obj); };
_Static_partitioned_for_each2<decltype(_UFirst), decltype(_Count), decltype(_Ctor_fn)> _Operation{
_Hw_threads, _Count, _Ctor_fn};
using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>;
using _Ctor_fn = _Inplace_value_construct_fn<_Ty>;
_Static_partitioned_for_each2<decltype(_UFirst), decltype(_Count), _Ctor_fn> _Operation{
_Hw_threads, _Count, _Ctor_fn{}};
_Operation._Basis._Populate(_Operation._Team, _UFirst);
_STD _Run_chunked_parallel_work(_Hw_threads, _Operation);
return;
Expand Down Expand Up @@ -5176,10 +5197,10 @@ _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, con
const size_t _Hw_threads = _CSTD __std_parallel_algorithms_hw_threads();
if (_Hw_threads > 1 && _Count >= 2) { // parallelize on multiprocessor machines with at least 2 elements
_TRY_BEGIN
using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>;
auto _Ctor_fn = [](_Ty& _Obj) { _STD _Construct_in_place(_Obj); };
_Static_partitioned_for_each2<decltype(_UFirst), decltype(_Count), decltype(_Ctor_fn)> _Operation{
_Hw_threads, _Count, _Ctor_fn};
using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>;
using _Ctor_fn = _Inplace_value_construct_fn<_Ty>;
_Static_partitioned_for_each2<decltype(_UFirst), decltype(_Count), _Ctor_fn> _Operation{
_Hw_threads, _Count, _Ctor_fn{}};
_STD _Seek_wrapped(_First, _Operation._Basis._Populate(_Operation._Team, _UFirst));
_STD _Run_chunked_parallel_work(_Hw_threads, _Operation);
return _First;
Expand Down
2 changes: 1 addition & 1 deletion stl/inc/experimental/filesystem
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,7 @@ public:
path& append(const basic_string<_Elem, _Traits, _Alloc>& _Str0) { // append arbitrary source string
string_type _Str(_Str0.size(), L'\0');
// convert _Elem and '/' to '\'
_STD transform(_Str0.begin(), _Str0.end(), _Str.begin(), [](const _Elem _Ch) {
_STD transform(_Str0.begin(), _Str0.end(), _Str.begin(), [](const _Elem _Ch) _STATIC_CALL_OPERATOR {
auto _Wch = static_cast<wchar_t>(_Ch);
if (_Wch == _FS_SLASH) {
_Wch = _FS_PREF;
Expand Down
4 changes: 2 additions & 2 deletions stl/inc/filesystem
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ namespace filesystem {
}

struct _Is_slash_oper { // predicate testing if input is a preferred-separator or fallback-separator
_NODISCARD constexpr bool operator()(const wchar_t _Ch) const {
_NODISCARD _STATIC_CALL_OPERATOR constexpr bool operator()(const wchar_t _Ch) _CONST_CALL_OPERATOR {
return _Ch == L'\\' || _Ch == L'/';
}
};
Expand Down Expand Up @@ -4445,7 +4445,7 @@ template <>
struct hash<filesystem::path> {
using _ARGUMENT_TYPE_NAME _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS = filesystem::path;
using _RESULT_TYPE_NAME _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS = size_t;
_NODISCARD size_t operator()(const filesystem::path& _Path) const noexcept {
_NODISCARD _STATIC_CALL_OPERATOR size_t operator()(const filesystem::path& _Path) _CONST_CALL_OPERATOR noexcept {
return _STD filesystem::hash_value(_Path);
}
};
Expand Down
Loading

0 comments on commit 2fa1641

Please sign in to comment.