Skip to content

Commit

Permalink
[inplace_vector] Fix iter-pair ctor for non-assignable value_type
Browse files Browse the repository at this point in the history
  • Loading branch information
Quuxplusone committed Oct 21, 2023
1 parent b509fc4 commit 127a6fb
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 2 deletions.
28 changes: 26 additions & 2 deletions include/sg14/inplace_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,20 @@ class inplace_vector : ipvbase_assignable<T>, ipvbase_t<T, N> {
constexpr explicit inplace_vector(size_t n, const value_type& value) { assign(n, value); }

template<class It, std::enable_if_t<std::is_base_of_v<std::input_iterator_tag, typename std::iterator_traits<It>::iterator_category>, int> = 0>
constexpr explicit inplace_vector(It first, It last) { assign(first, last); }
constexpr explicit inplace_vector(It first, It last) {
if constexpr (std::is_base_of_v<std::random_access_iterator_tag, typename std::iterator_traits<It>::iterator_category>) {
size_t n = last - first;
if (n > N) {
SG14_INPLACE_VECTOR_THROW(std::bad_alloc());
}
std::uninitialized_copy_n(first, n, data());
set_size_(n);
} else {
for (; first != last; ++first) {
emplace_back(*first);
}
}
}

constexpr void assign(std::initializer_list<value_type> il) { assign(il.begin(), il.end()); }

Expand Down Expand Up @@ -284,7 +297,18 @@ class inplace_vector : ipvbase_assignable<T>, ipvbase_t<T, N> {
template<std::ranges::input_range R>
requires std::convertible_to<std::ranges::range_reference_t<R>, value_type>
constexpr explicit inplace_vector(std::from_range_t, R&& rg) {
assign_range(rg);
if constexpr (std::ranges::sized_range<R>) {
size_t n = std::ranges::size(rg);
if (n > N) {
SG14_INPLACE_VECTOR_THROW(std::bad_alloc());
}
std::ranges::uninitialized_copy_n(std::ranges::begin(rg), n, data(), std::unreachable_sentinel);
set_size_(n);
} else {
for (auto&& e : rg) {
emplace_back(decltype(e)(e));
}
}
}

template<std::ranges::input_range R>
Expand Down
82 changes: 82 additions & 0 deletions test/inplace_vector_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,28 @@ TEST(inplace_vector, ConstructorsThrow)
}
}

TEST(inplace_vector, IterPairNonAssignable)
{
struct NA {
std::string s_;
NA(const char *s) : s_(s) {}
NA(NA&&) = delete;
NA& operator=(NA&&) = delete;
bool operator==(const char *s) const { return s_ == s; }
};
const char *a[] = {"1", "2", "3"};
{
auto v = sg14::inplace_vector<NA, 10>(a, a+3);
EXPECT_EQ(v, Seq("1", "2", "3"));
}
#if defined(__cpp_lib_ranges_to_container)
{
auto v = sg14::inplace_vector<NA, 10>(std::from_range, a);
EXPECT_EQ(v, Seq("1", "2", "3"));
}
#endif
}

TEST(inplace_vector, Copying)
{
{
Expand Down Expand Up @@ -809,6 +831,66 @@ TEST(inplace_vector, InsertMulti)
}
}

TEST(inplace_vector, Assign)
{
{
using V = sg14::inplace_vector<int, 5>;
V v;
int a[] = {1, 2, 3, 4, 5, 6};
v.assign(a, a+2);
static_assert(std::is_same_v<decltype(v.assign(a, a+2)), void>);
EXPECT_EQ(v, (V{1, 2}));
v.assign(a+2, a+6);
EXPECT_EQ(v, (V{3, 4, 5, 6}));
v.assign(a, a+2);
EXPECT_EQ(v, (V{1, 2}));
ASSERT_THROW(v.assign(a, a+6), std::bad_alloc);
EXPECT_LE(v.size(), 5u);
}
{
using V = sg14::inplace_vector<std::string, 5>;
V v;
const char *a[] = {"1", "2", "3", "4", "5", "6"};
v.assign(a, a+2);
EXPECT_EQ(v, Seq("1", "2"));
v.assign(a+2, a+6);
EXPECT_EQ(v, Seq("3", "4", "5", "6"));
v.assign(a, a+2);
EXPECT_EQ(v, Seq("1", "2"));
ASSERT_THROW(v.assign(a, a+6), std::bad_alloc);
EXPECT_LE(v.size(), 5u);
}
{
using V = sg14::inplace_vector<int, 5>;
V v;
auto iss = std::istringstream("1 2");
v.assign(std::istream_iterator<int>(iss), {});
EXPECT_EQ(v, (V{1, 2}));
iss = std::istringstream("4 5 6 7");
v.assign(std::istream_iterator<int>(iss), {});
EXPECT_EQ(v, (V{4, 5, 6, 7}));
iss = std::istringstream("1 2");
v.assign(std::istream_iterator<int>(iss), {});
EXPECT_EQ(v, (V{1, 2}));
iss = std::istringstream("1 2 3 4 5 6");
ASSERT_THROW(v.assign(std::istream_iterator<int>(iss), {}), std::bad_alloc);
EXPECT_LE(v.size(), 5u);
}
{
using V = sg14::inplace_vector<MoveOnly, 5>;
const char *a[] = {"1", "2", "3", "4", "5", "6"};
V v;
v.assign(a, a+2);
EXPECT_EQ(v, Seq("1", "2"));
v.assign(a+2, a+6);
EXPECT_EQ(v, Seq("3", "4", "5", "6"));
v.assign(a, a+2);
EXPECT_EQ(v, Seq("1", "2"));
ASSERT_THROW(v.assign(a, a+6), std::bad_alloc);
EXPECT_LE(v.size(), 5u);
}
}

TEST(inplace_vector, AssignRange)
{
#if defined(__cpp_lib_ranges_to_container)
Expand Down

0 comments on commit 127a6fb

Please sign in to comment.