mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
Add container overloads for absl::c_copy and absl::c_copy_n
These versions accept a container as the output destination. The primary motivation for these overloads is to add bounds checking. We determine if an object is a container by checking if they support `std::begin`/`std::end`. PiperOrigin-RevId: 907840607 Change-Id: I10430108dc734f1e93c0cef6ca33d251520ac3e8
This commit is contained in:
committed by
Copybara-Service
parent
a5c21433c7
commit
f9adcd0f0c
@@ -17,7 +17,6 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <forward_list>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
@@ -26,7 +25,6 @@
|
||||
#include <ostream>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <type_traits>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <valarray>
|
||||
@@ -38,7 +36,6 @@
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/random/random.h"
|
||||
#include "absl/types/span.h"
|
||||
|
||||
@@ -715,190 +712,6 @@ TEST(MutatingTest, CopyN) {
|
||||
EXPECT_EQ(expected, actual);
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNWithNegativeN) {
|
||||
#ifdef _LIBCPP_VERSION
|
||||
GTEST_SKIP() << "libc++ does not handle negative counts correctly";
|
||||
#else
|
||||
const std::vector<int> input = {1, 2, 3};
|
||||
std::vector<int> actual = {0, 0, 0};
|
||||
absl::c_copy_n(input, -1, actual.begin());
|
||||
EXPECT_THAT(actual, ElementsAre(0, 0, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyToContainer) {
|
||||
const std::vector<int> input = {1, 2, 3};
|
||||
std::vector<int> actual = {0, 0, 0, 4, 5};
|
||||
absl::c_copy(input, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToContainer) {
|
||||
const std::vector<int> input = {1, 2, 3, 4, 5};
|
||||
std::vector<int> actual = {0, 0, 0, 0, 0};
|
||||
absl::c_copy_n(input, 2, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(1, 2, 0, 0, 0));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToContainerWithZeroN) {
|
||||
const std::vector<int> input = {1, 2, 3, 4, 5};
|
||||
std::vector<int> actual = {0, 0, 0, 0, 0};
|
||||
absl::c_copy_n(input, 0, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(0, 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToContainerWithNegativeN) {
|
||||
#ifdef _LIBCPP_VERSION
|
||||
GTEST_SKIP() << "libc++ does not handle negative counts correctly";
|
||||
#else
|
||||
const std::vector<int> input = {1, 2, 3};
|
||||
std::vector<int> actual = {0, 0, 0};
|
||||
absl::c_copy_n(input, -1, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(0, 0, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyToDifferentContainerType) {
|
||||
const std::list<int> input = {1, 2, 3};
|
||||
std::array<int, 5> actual = {0, 0, 0, 4, 5};
|
||||
absl::c_copy(input, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToDifferentContainerType) {
|
||||
const std::list<int> input = {1, 2, 3, 4, 5};
|
||||
std::array<int, 5> actual = {0, 0, 0, 0, 0};
|
||||
absl::c_copy_n(input, 2, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(1, 2, 0, 0, 0));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyToCArray) {
|
||||
const std::vector<int> input = {1, 2, 3};
|
||||
int actual[5] = {0, 0, 0, 4, 5};
|
||||
absl::c_copy(input, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToCArray) {
|
||||
const std::vector<int> input = {1, 2, 3, 4, 5};
|
||||
int actual[5] = {0, 0, 0, 0, 0};
|
||||
absl::c_copy_n(input, 2, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(1, 2, 0, 0, 0));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyFromCArray) {
|
||||
const int input[5] = {1, 2, 3, 4, 5};
|
||||
std::vector<int> actual = {0, 0, 0, 0, 0};
|
||||
absl::c_copy(input, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNFromCArray) {
|
||||
const int input[5] = {1, 2, 3, 4, 5};
|
||||
std::vector<int> actual = {0, 0, 0, 0, 0};
|
||||
absl::c_copy_n(input, 2, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(1, 2, 0, 0, 0));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyContainerWithNoSizeMethod) {
|
||||
const std::forward_list<int> input = {1, 2, 3};
|
||||
std::forward_list<int> actual = {0, 0, 0, 4, 5};
|
||||
absl::c_copy(input, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNContainerWithNoSizeMethod) {
|
||||
const std::forward_list<int> input = {1, 2, 3, 4, 5};
|
||||
std::forward_list<int> actual = {0, 0, 0, 0, 0};
|
||||
absl::c_copy_n(input, 2, actual);
|
||||
EXPECT_THAT(actual, ElementsAre(1, 2, 0, 0, 0));
|
||||
}
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
bool IsHardened() {
|
||||
bool hardened = false;
|
||||
ABSL_HARDENING_ASSERT([&hardened]() {
|
||||
hardened = true;
|
||||
return true;
|
||||
}());
|
||||
return hardened;
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyToCArrayInvalidSize) {
|
||||
const std::vector<int> input = {1, 2, 3};
|
||||
int actual[2] = {0, 0};
|
||||
if (IsHardened()) {
|
||||
EXPECT_DEATH(absl::c_copy(input, actual), "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToCArrayInvalidSize) {
|
||||
const std::vector<int> input = {1, 2, 3};
|
||||
int actual[2] = {0, 0};
|
||||
if (IsHardened()) {
|
||||
EXPECT_DEATH(absl::c_copy_n(input, 3, actual), "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToCArrayNGreaterThanInput) {
|
||||
const std::vector<int> input = {1, 2, 3};
|
||||
int actual[4] = {0, 0, 0, 0};
|
||||
if (IsHardened()) {
|
||||
EXPECT_DEATH(absl::c_copy_n(input, 4, actual), "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyToContainerInvalidSize) {
|
||||
const std::list<int> input = {1, 2, 3, 4, 5};
|
||||
std::list<int> actual = {0, 0, 0};
|
||||
if (IsHardened()) {
|
||||
EXPECT_DEATH(absl::c_copy(input, actual), "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToContainerNGreaterThanInput) {
|
||||
const std::vector<int> input = {1, 2, 3};
|
||||
std::vector<int> actual = {0, 0, 0, 0};
|
||||
if (IsHardened()) {
|
||||
EXPECT_DEATH(absl::c_copy_n(input, 4, actual), "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToContainerNGreaterThanOutput) {
|
||||
const std::vector<int> input = {1, 2, 3};
|
||||
std::vector<int> actual = {0, 0};
|
||||
if (IsHardened()) {
|
||||
EXPECT_DEATH(absl::c_copy_n(input, 3, actual), "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyToForwardListInvalidSize) {
|
||||
const std::forward_list<int> input = {1, 2, 3, 4, 5};
|
||||
std::forward_list<int> actual = {0, 0, 0};
|
||||
if (IsHardened()) {
|
||||
EXPECT_DEATH(absl::c_copy(input, actual), "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToForwardListNGreaterThanInput) {
|
||||
const std::forward_list<int> input = {1, 2, 3};
|
||||
std::forward_list<int> actual = {0, 0, 0, 0};
|
||||
if (IsHardened()) {
|
||||
EXPECT_DEATH(absl::c_copy_n(input, 4, actual), "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MutatingTest, CopyNToForwardListNGreaterThanOutput) {
|
||||
const std::forward_list<int> input = {1, 2, 3};
|
||||
std::forward_list<int> actual = {0, 0};
|
||||
if (IsHardened()) {
|
||||
EXPECT_DEATH(absl::c_copy_n(input, 3, actual), "");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
TEST(MutatingTest, CopyIf) {
|
||||
const std::list<int> input = {1, 2, 3};
|
||||
std::vector<int> output;
|
||||
@@ -2416,42 +2229,4 @@ TEST(ConstexprTest, PartialSumWithPredicate) {
|
||||
#endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&
|
||||
// ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
|
||||
|
||||
template <typename Container, typename Output, typename = void>
|
||||
struct CanCopy : std::false_type {};
|
||||
template <typename Container, typename Output>
|
||||
struct CanCopy<Container, Output,
|
||||
absl::void_t<decltype(absl::c_copy(std::declval<Container>(),
|
||||
std::declval<Output>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename Container, typename Output, typename = void>
|
||||
struct CanCopyN : std::false_type {};
|
||||
template <typename Container, typename Output>
|
||||
struct CanCopyN<Container, Output,
|
||||
absl::void_t<decltype(absl::c_copy_n(
|
||||
std::declval<Container>(), std::declval<ptrdiff_t>(),
|
||||
std::declval<Output>()))>> : std::true_type {};
|
||||
|
||||
TEST(CanCopyTest, CopyToMultiDimArray) {
|
||||
static_assert(CanCopy<std::vector<int>, int (&)[10]>::value);
|
||||
static_assert(!CanCopy<std::vector<int>, int (&)[2][2]>::value);
|
||||
static_assert(CanCopyN<std::vector<int>, int (&)[10]>::value);
|
||||
static_assert(!CanCopyN<std::vector<int>, int (&)[2][2]>::value);
|
||||
|
||||
static_assert(CanCopy<int[10], int (&)[10]>::value);
|
||||
static_assert(!CanCopy<int[10], int (&)[2][2]>::value);
|
||||
static_assert(CanCopyN<int[10], int (&)[10]>::value);
|
||||
static_assert(!CanCopyN<int[10], int (&)[2][2]>::value);
|
||||
static_assert(!CanCopy<int[2][2], int (&)[4]>::value);
|
||||
static_assert(!CanCopy<int[2][2], int (&)[2][2]>::value);
|
||||
static_assert(!CanCopyN<int[2][2], int (&)[4]>::value);
|
||||
static_assert(!CanCopyN<int[2][2], int (&)[2][2]>::value);
|
||||
}
|
||||
|
||||
TEST(CanCopyTest, BlockNonWritableIterators) {
|
||||
using Vec = std::vector<int>;
|
||||
|
||||
static_assert(CanCopy<Vec, Vec::iterator>::value);
|
||||
static_assert(CanCopy<Vec, std::back_insert_iterator<Vec>>::value);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user