-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Implement ranges::uninitialized_meow #1164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
StephanTLavavej
merged 25 commits into
microsoft:master
from
miscco:ranges_uninitialized_default_construct
Sep 22, 2020
Merged
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
d12c8b0
Implement several specialized memory range algorithms:
miscco 577eab3
Address review comments
miscco 9415328
Remove noexcept case without _Backout as ++_IFirst could throw too
miscco f2d424e
Use early returns everywhere
miscco 3ffbf82
Bring back the specializations as we have nothrow iterators
miscco 580f1ba
Cleanup memset
miscco a995b00
Define and use voidify_iter
miscco e2e3a32
Fix derp
miscco c925844
Only move once
miscco 5f5d1cb
Fix missing increment
miscco b9ba5f7
Use _Iter_ref-t?
miscco 96dee36
Merge branch 'master' into ranges_uninitialized_default_construct
miscco 154ee95
Expand uninitialized_copy test for possibly throwing copy construction
miscco adc4253
unchecked_copy uses _Copy_memmove ...
miscco e4e1eb3
unname unused variable
miscco 8031035
Expand all the tests
miscco 03a412d
Remove unneeded specializations that are not better than _Backout
miscco fec98ef
Address review comments
miscco b1eaed6
Thanks vscode
miscco aaccea9
Add macro-defense parentheses.
StephanTLavavej 7f31e9e
Apply suggestions from code review
miscco 3b7e991
Address review comments
miscco 282f1b3
Saving a file helps...
miscco 1397829
Use _Fill_memset for correctness
StephanTLavavej 6a4aa21
Merge branch 'master' into ranges_uninitialized_default_construct
StephanTLavavej File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/env.lst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| RUNALL_INCLUDE ..\concepts_matrix.lst |
197 changes: 197 additions & 0 deletions
197
tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,197 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #include <algorithm> | ||
| #include <cassert> | ||
| #include <concepts> | ||
| #include <memory> | ||
| #include <ranges> | ||
| #include <span> | ||
| #include <utility> | ||
|
|
||
| #include <range_algorithm_support.hpp> | ||
|
|
||
| using namespace std; | ||
|
|
||
| // Validate that uninitialized_copy_result aliases in_out_result | ||
| STATIC_ASSERT(same_as<ranges::uninitialized_copy_result<int, double>, ranges::in_out_result<int, double>>); | ||
|
|
||
| // Validate dangling story | ||
| STATIC_ASSERT(same_as<decltype(ranges::uninitialized_copy(borrowed<false>{}, borrowed<false>{})), | ||
| ranges::uninitialized_copy_result<ranges::dangling, ranges::dangling>>); | ||
| STATIC_ASSERT(same_as<decltype(ranges::uninitialized_copy(borrowed<false>{}, borrowed<true>{})), | ||
| ranges::uninitialized_copy_result<ranges::dangling, int*>>); | ||
| STATIC_ASSERT(same_as<decltype(ranges::uninitialized_copy(borrowed<true>{}, borrowed<false>{})), | ||
| ranges::uninitialized_copy_result<int*, ranges::dangling>>); | ||
| STATIC_ASSERT(same_as<decltype(ranges::uninitialized_copy(borrowed<true>{}, borrowed<true>{})), | ||
| ranges::uninitialized_copy_result<int*, int*>>); | ||
|
|
||
| enum class CanThrowAtCopyConstruction : bool { no, yes }; | ||
|
|
||
| template <CanThrowAtCopyConstruction CanThrow> | ||
| struct int_wrapper { | ||
| inline static int constructions = 0; | ||
| inline static int destructions = 0; | ||
|
|
||
| static void clear_counts() { | ||
| constructions = 0; | ||
| destructions = 0; | ||
| } | ||
|
|
||
| static constexpr int magic_throwing_val = 29; | ||
| int val = 10; | ||
|
|
||
| int_wrapper() { | ||
| ++constructions; | ||
| } | ||
| int_wrapper(int x) : val{x} { | ||
| ++constructions; | ||
| } | ||
|
|
||
| int_wrapper(const int_wrapper& that) noexcept(!static_cast<bool>(CanThrow)) { | ||
| if constexpr (CanThrow == CanThrowAtCopyConstruction::yes) { | ||
| if (that.val == magic_throwing_val) { | ||
| throw magic_throwing_val; | ||
| } | ||
| } | ||
|
|
||
| val = that.val; | ||
| ++constructions; | ||
| } | ||
|
|
||
| ~int_wrapper() { | ||
| ++destructions; | ||
| } | ||
|
|
||
| int_wrapper& operator=(const int_wrapper&) { | ||
CaseyCarter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // Shall never be used as we construct in place | ||
| throw magic_throwing_val + 1; | ||
miscco marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| auto operator<=>(const int_wrapper&) const = default; | ||
| }; | ||
|
|
||
| template <class T, size_t N> | ||
| struct holder { | ||
| STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); | ||
| alignas(T) unsigned char space[N * sizeof(T)]; | ||
|
|
||
| auto as_span() { | ||
| return span<T, N>{reinterpret_cast<T*>(space + 0), N}; | ||
| } | ||
| }; | ||
|
|
||
| template <class R> | ||
| void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy | ||
| for (auto& e : r) { | ||
| destroy_at(&e); | ||
| } | ||
| } | ||
|
|
||
| template <CanThrowAtCopyConstruction CanThrow> | ||
| struct instantiator { | ||
| static constexpr int expected_output[] = {13, 55, 12345}; | ||
| static constexpr int expected_input[] = {13, 55, 12345}; | ||
|
|
||
| template <ranges::input_range R, ranges::forward_range W> | ||
| static void call() { | ||
| using ranges::uninitialized_copy, ranges::uninitialized_copy_result, ranges::equal, ranges::equal_to, | ||
| ranges::iterator_t; | ||
| using wrapper = int_wrapper<CanThrow>; | ||
|
|
||
| { // Validate range overload | ||
| wrapper input[3] = {13, 55, 12345}; | ||
| R wrapped_input{input}; | ||
| holder<wrapper, 3> mem; | ||
| W wrapped_output{mem.as_span()}; | ||
|
|
||
| wrapper::clear_counts(); | ||
| const same_as<uninitialized_copy_result<iterator_t<R>, iterator_t<W>>> auto result = | ||
| uninitialized_copy(wrapped_input, wrapped_output); | ||
| assert(wrapper::constructions == 3); | ||
| assert(wrapper::destructions == 0); | ||
| assert(result.in == wrapped_input.end()); | ||
| assert(result.out == wrapped_output.end()); | ||
| assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); | ||
| assert(equal(input, expected_input, equal_to{}, &wrapper::val)); | ||
| not_ranges_destroy(wrapped_output); | ||
| assert(wrapper::constructions == 3); | ||
| assert(wrapper::destructions == 3); | ||
| } | ||
|
|
||
| { // Validate iterator overload | ||
| wrapper input[3] = {13, 55, 12345}; | ||
| R wrapped_input{input}; | ||
| holder<wrapper, 3> mem; | ||
| W wrapped_output{mem.as_span()}; | ||
|
|
||
| wrapper::clear_counts(); | ||
| const same_as<uninitialized_copy_result<iterator_t<R>, iterator_t<W>>> auto result = uninitialized_copy( | ||
| wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin(), wrapped_output.end()); | ||
| assert(wrapper::constructions == 3); | ||
| assert(wrapper::destructions == 0); | ||
| assert(result.in == wrapped_input.end()); | ||
| assert(result.out == wrapped_output.end()); | ||
| assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); | ||
| assert(equal(input, expected_input, equal_to{}, &wrapper::val)); | ||
| not_ranges_destroy(wrapped_output); | ||
| assert(wrapper::constructions == 3); | ||
| assert(wrapper::destructions == 3); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| struct throwing_test { | ||
| using wrapper = int_wrapper<CanThrowAtCopyConstruction::yes>; | ||
| static constexpr int expected_input[] = {13, 55, wrapper::magic_throwing_val, 12345}; | ||
|
|
||
| template <ranges::input_range R, ranges::forward_range W> | ||
| static void call() { | ||
|
|
||
miscco marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // Validate only range overload (one is plenty since they both use the same backend) | ||
| wrapper input[] = {13, 55, wrapper::magic_throwing_val, 12345}; | ||
| R wrapped_input{input}; | ||
| holder<wrapper, 4> mem; | ||
| W wrapped_output{mem.as_span()}; | ||
|
|
||
| wrapper::clear_counts(); | ||
| try { | ||
| (void) ranges::uninitialized_copy(wrapped_input, wrapped_output); | ||
| assert(false); | ||
| } catch (int i) { | ||
| assert(i == wrapper::magic_throwing_val); | ||
| } catch (...) { | ||
| assert(false); | ||
| } | ||
| assert(wrapper::constructions == 2); | ||
| assert(wrapper::destructions == 2); | ||
| assert(ranges::equal(input, expected_input, ranges::equal_to{}, &wrapper::val)); | ||
| } | ||
| }; | ||
|
|
||
| template <test::ProxyRef IsProxy, CanThrowAtCopyConstruction CanThrow> | ||
| using test_input = test::range<test::input, int_wrapper<CanThrow>, test::Sized::no, test::CanDifference::no, | ||
| test::Common::no, test::CanCompare::yes, IsProxy>; | ||
| template <CanThrowAtCopyConstruction CanThrow> | ||
| using test_output = test::range<test::fwd, int_wrapper<CanThrow>, test::Sized::no, test::CanDifference::no, | ||
| test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; | ||
|
|
||
| int main() { | ||
| // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It | ||
| // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. | ||
|
|
||
| instantiator<CanThrowAtCopyConstruction::yes>::call<test_input<test::ProxyRef::no, CanThrowAtCopyConstruction::yes>, | ||
| test_output<CanThrowAtCopyConstruction::yes>>(); | ||
| instantiator<CanThrowAtCopyConstruction::yes>::call< | ||
| test_input<test::ProxyRef::yes, CanThrowAtCopyConstruction::yes>, | ||
| test_output<CanThrowAtCopyConstruction::yes>>(); | ||
| instantiator<CanThrowAtCopyConstruction::no>::call<test_input<test::ProxyRef::no, CanThrowAtCopyConstruction::no>, | ||
| test_output<CanThrowAtCopyConstruction::no>>(); | ||
| instantiator<CanThrowAtCopyConstruction::no>::call<test_input<test::ProxyRef::yes, CanThrowAtCopyConstruction::no>, | ||
| test_output<CanThrowAtCopyConstruction::no>>(); | ||
|
|
||
| throwing_test::call<test_input<test::ProxyRef::no, CanThrowAtCopyConstruction::yes>, | ||
| test_output<CanThrowAtCopyConstruction::yes>>(); | ||
| throwing_test::call<test_input<test::ProxyRef::yes, CanThrowAtCopyConstruction::yes>, | ||
| test_output<CanThrowAtCopyConstruction::yes>>(); | ||
| } | ||
4 changes: 4 additions & 0 deletions
4
tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| RUNALL_INCLUDE ..\concepts_matrix.lst |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.