Implement ranges::fill and ranges::fill_n (#904)

This commit is contained in:
ahanamuk 2020-07-02 10:24:14 -04:00 коммит произвёл GitHub
Родитель 5e3423a377
Коммит 123b2b2bfa
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 228 добавлений и 0 удалений

Просмотреть файл

@ -3003,6 +3003,85 @@ _FwdIt2 replace_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _
}
#endif // _HAS_CXX17
#ifdef __cpp_lib_concepts
namespace ranges {
// VARIABLE ranges::fill
class _Fill_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;
template <class _Ty, output_iterator<const _Ty&> _It, sentinel_for<_It> _Se>
constexpr _It operator()(_It _First, _Se _Last, const _Ty& _Value) const {
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_STD move(_First));
const auto _ULast = _Get_unwrapped(_STD move(_Last));
if constexpr (_Fill_memset_is_safe<decltype(_UFirst), _Ty>) {
#ifdef __cpp_lib_is_constant_evaluated
if (!_STD is_constant_evaluated())
#endif // __cpp_lib_is_constant_evaluated
{
const auto _Distance = static_cast<size_t>(_ULast - _UFirst);
_CSTD memset(_UFirst, static_cast<unsigned char>(_Value), _Distance);
_UFirst += _Distance;
_Seek_wrapped(_First, _UFirst);
return _First;
}
}
for (; _UFirst != _ULast; ++_UFirst) {
*_UFirst = _Value;
}
_Seek_wrapped(_First, _STD move(_UFirst));
return _First;
}
template <class _Ty, output_range<const _Ty&> _Rng>
constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, const _Ty& _Value) const {
auto _First = _RANGES begin(_Range);
_Seek_wrapped(_First, (*this)(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Value));
return _First;
}
};
inline constexpr _Fill_fn fill{_Not_quite_object::_Construct_tag{}};
// VARIABLE ranges::fill_n
class _Fill_n_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;
template <class _Ty, output_iterator<const _Ty&> _It>
constexpr _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Value) const {
if (_Count > 0) {
auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count);
if constexpr (_Fill_memset_is_safe<decltype(_UFirst), _Ty>) {
#ifdef __cpp_lib_is_constant_evaluated
if (!_STD is_constant_evaluated())
#endif // __cpp_lib_is_constant_evaluated
{
_CSTD memset(_UFirst, static_cast<unsigned char>(_Value), static_cast<size_t>(_Count));
_UFirst += _Count;
_Seek_wrapped(_First, _UFirst); // no need to move since _UFirst is a pointer
return _First;
}
}
for (; _Count > 0; ++_UFirst, (void) --_Count) {
*_UFirst = _Value;
}
_Seek_wrapped(_First, _STD move(_UFirst));
}
return _First;
}
};
inline constexpr _Fill_n_fn fill_n{_Not_quite_object::_Construct_tag{}};
} // namespace ranges
#endif // __cpp_lib_concepts
// FUNCTION TEMPLATE generate
template <class _FwdIt, class _Fn>
_CONSTEXPR20 void generate(_FwdIt _First, _FwdIt _Last, _Fn _Func) { // replace [_First, _Last) with _Func()

Просмотреть файл

@ -807,6 +807,55 @@ struct with_input_ranges {
}
};
template <class Continuation, class Element = int>
struct with_output_ranges {
template <class... Args>
static constexpr void call() {
using namespace test;
// For all ranges, IsCommon implies Eq.
// For single-pass ranges, Eq is uninteresting without IsCommon (there's only one valid iterator
// value at a time, and no reason to compare it with itself for equality).
Continuation::template call<Args...,
range<output, Element, Sized::no, CanDifference::no, Common::no, CanCompare::no, ProxyRef::no>>();
Continuation::template call<Args...,
range<output, Element, Sized::no, CanDifference::no, Common::no, CanCompare::no, ProxyRef::yes>>();
Continuation::template call<Args...,
range<output, Element, Sized::no, CanDifference::no, Common::yes, CanCompare::yes, ProxyRef::no>>();
Continuation::template call<Args...,
range<output, Element, Sized::no, CanDifference::no, Common::yes, CanCompare::yes, ProxyRef::yes>>();
Continuation::template call<Args...,
range<output, Element, Sized::no, CanDifference::yes, Common::no, CanCompare::no, ProxyRef::no>>();
Continuation::template call<Args...,
range<output, Element, Sized::no, CanDifference::yes, Common::no, CanCompare::no, ProxyRef::yes>>();
Continuation::template call<Args...,
range<output, Element, Sized::no, CanDifference::yes, Common::yes, CanCompare::yes, ProxyRef::no>>();
Continuation::template call<Args...,
range<output, Element, Sized::no, CanDifference::yes, Common::yes, CanCompare::yes, ProxyRef::yes>>();
Continuation::template call<Args...,
range<output, Element, Sized::yes, CanDifference::no, Common::no, CanCompare::no, ProxyRef::no>>();
Continuation::template call<Args...,
range<output, Element, Sized::yes, CanDifference::no, Common::no, CanCompare::no, ProxyRef::yes>>();
Continuation::template call<Args...,
range<output, Element, Sized::yes, CanDifference::no, Common::yes, CanCompare::yes, ProxyRef::no>>();
Continuation::template call<Args...,
range<output, Element, Sized::yes, CanDifference::no, Common::yes, CanCompare::yes, ProxyRef::yes>>();
Continuation::template call<Args...,
range<output, Element, Sized::yes, CanDifference::yes, Common::no, CanCompare::no, ProxyRef::no>>();
Continuation::template call<Args...,
range<output, Element, Sized::yes, CanDifference::yes, Common::no, CanCompare::no, ProxyRef::yes>>();
Continuation::template call<Args...,
range<output, Element, Sized::yes, CanDifference::yes, Common::yes, CanCompare::yes, ProxyRef::no>>();
Continuation::template call<Args...,
range<output, Element, Sized::yes, CanDifference::yes, Common::yes, CanCompare::yes, ProxyRef::yes>>();
with_forward_ranges<Continuation, Element>::template call<Args...>();
}
};
template <class Continuation, class Element = int>
struct with_input_iterators {
template <class... Args>
@ -854,6 +903,11 @@ struct with_difference {
}
};
template <class Instantiator, class Element = int>
constexpr void test_out() {
with_output_ranges<Instantiator, Element>::call();
}
template <class Instantiator, class Element = int>
constexpr void test_in() {
with_input_ranges<Instantiator, Element>::call();

Просмотреть файл

@ -245,6 +245,8 @@ tests\P0896R4_ranges_alg_copy_n
tests\P0896R4_ranges_alg_count
tests\P0896R4_ranges_alg_count_if
tests\P0896R4_ranges_alg_equal
tests\P0896R4_ranges_alg_fill
tests\P0896R4_ranges_alg_fill_n
tests\P0896R4_ranges_alg_find
tests\P0896R4_ranges_alg_find_end
tests\P0896R4_ranges_alg_find_first_of

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\concepts_matrix.lst

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <algorithm>
#include <cassert>
#include <concepts>
#include <ranges>
#include <utility>
#include <range_algorithm_support.hpp>
struct instantiator {
template <class Out>
static constexpr void call() {
using ranges::fill;
{
int output[] = {13, 42, 1367};
const int value = 7;
auto result = fill(ranges::begin(output), ranges::end(output), value);
for (const auto& elem : output) {
assert(elem == value);
}
assert(result == ranges::end(output));
}
{ // Validate ranges overload
int output[] = {13, 42, 1367};
const int value = 13;
auto result = fill(output, value);
for (const auto& elem : output) {
assert(elem == value);
}
assert(result == ranges::end(output));
}
}
};
int main() {
STATIC_ASSERT((test_out<instantiator>(), true));
test_out<instantiator>();
}

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\concepts_matrix.lst

Просмотреть файл

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <algorithm>
#include <cassert>
#include <concepts>
#include <ranges>
#include <utility>
#include <range_algorithm_support.hpp>
struct instantiator {
template <class Out>
static constexpr void call() {
using ranges::fill_n;
const int expected_output[] = {13, 42, 1367};
const int value = 7;
{
int output[] = {13, 42, 1367};
auto result = fill_n(ranges::begin(output), ranges::distance(output), value);
for (const auto& elem : output) {
assert(elem == value);
}
assert(result == ranges::end(output));
}
{
int output[] = {13, 42, 1367};
auto result = fill_n(ranges::begin(output), 0, value);
assert(ranges::equal(output, expected_output));
assert(result == ranges::begin(output));
}
{
int output[] = {13, 42, 1367};
auto result = fill_n(ranges::begin(output), -1, value);
assert(ranges::equal(output, expected_output));
assert(result == ranges::begin(output));
}
}
};
int main() {
STATIC_ASSERT((test_out<instantiator>(), true));
test_out<instantiator>();
}