Skip to content

Commit

Permalink
explicit dynarray copy constructor, and from_range
Browse files Browse the repository at this point in the history
Also operator =(const dynarray &&) = delete
  • Loading branch information
OleErikPeistorpet committed Jun 6, 2024
1 parent 4d35adf commit 3972bab
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 35 deletions.
4 changes: 2 additions & 2 deletions auxi/dynarray_detail.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include "core_util.h"
#include "util.h" // for from_range

#include <cstdint> // for uintptr_t
#include <stdexcept>
Expand Down Expand Up @@ -144,7 +144,7 @@ namespace oel::_detail
template< typename Range >
friend auto operator |(Range && r, ToDynarrPartial t)
{
return dynarray(static_cast<Range &&>(r), std::move(t)._a);
return dynarray(from_range, static_cast<Range &&>(r), std::move(t)._a);
}
};
}
44 changes: 23 additions & 21 deletions dynarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,15 @@ struct _toDynarrayFn
return _detail::ToDynarrPartial<Alloc>{std::move(a)};
}
};
//! Equivalent to `std::ranges::to<dynarray>` (piped)
//! `r | to_dynarray()` is equivalent to `r | std::ranges::to<dynarray>()`
/**
* Example, convert array of std::bitset to `dynarray<std::string>`:
@code
std::bitset<8> arr[] {3, 5, 7, 11};
auto result = arr | view::transform(OEL_MEMBER_FN(to_string)) | to_dynarray();
@endcode */
inline constexpr _toDynarrayFn to_dynarray;


//! Overloads generic unordered_erase(RandomAccessContainer &, Integral) (in range_algo.h)
template< typename T, typename A > inline
void unordered_erase(dynarray<T, A> & d, ptrdiff_t index) { d.unordered_erase(d.begin() + index); }
Expand Down Expand Up @@ -97,35 +102,27 @@ class dynarray
explicit dynarray(size_type size, Alloc a = Alloc{});
dynarray(size_type size, const T & val, Alloc a = Alloc{}) : _m(a) { append(size, val); }

/** @brief Equivalent to `std::vector(std::from_range, r, a)`, except `end(r)` is not needed if `r.size()` is valid
*
* To move instead of copy, wrap r with view::move (The same applies for all functions taking a range template)
*
* Example, construct from a standard istream with formatting (using Boost):
@code
#include <boost/range/istream_range.hpp>
auto result = dynarray(boost::range::istream_range<int>(someStream));
@endcode */
template< typename InputRange,
typename /*EnableIfRange*/ = iterator_t<InputRange>,
enable_if< !_detail::isSameSansCVRef<InputRange, dynarray> > = 0
>
explicit dynarray(InputRange && r, Alloc a = Alloc{}) : _m(a) { append(r); }

dynarray(std::initializer_list<T> il, Alloc a = Alloc{}) : _m(a) { append(il); }
//! Equivalent to `std::vector(std::from_range, r, a)`, except `end(r)` is not needed if `r.size()` is valid
/**
* To move instead of copy, wrap `r` with view::move (The same applies for all functions taking a range) */
template< typename InputRange >
dynarray(from_range_t, InputRange && r, Alloc a = Alloc{}) : _m(a) { append(r); }

dynarray(std::initializer_list<T> il, Alloc a = Alloc{}) : _m(a) { append(il); }

dynarray(dynarray && other) noexcept : _m(std::move(other._m)) {}
dynarray(dynarray && other, Alloc a);
dynarray(const dynarray & other) : dynarray(other,
explicit dynarray(const dynarray & other) : dynarray(other,
_alloTrait::select_on_container_copy_construction(other._m)) {}
dynarray(const dynarray & other, Alloc a) : _m(a) { append(other); }
explicit dynarray(const dynarray & other, Alloc a) : _m(a) { append(other); }

~dynarray() noexcept;

dynarray & operator =(dynarray && other) &
noexcept(_alloTrait::propagate_on_container_move_assignment::value or _alloTrait::is_always_equal::value);
//! Requires that allocator_type is always equal or does not have propagate_on_container_copy_assignment
dynarray & operator =(const dynarray & other) &;
dynarray & operator =(const dynarray &&) = delete;

dynarray & operator =(std::initializer_list<T> il) & { assign(il); return *this; }

Expand Down Expand Up @@ -931,12 +928,17 @@ typename dynarray<T, Alloc>::iterator dynarray<T, Alloc>::erase(iterator first,


template< typename InputRange, typename Alloc = allocator<> >
explicit dynarray(InputRange &&, Alloc = {})
dynarray(from_range_t, InputRange &&, Alloc = {})
-> dynarray<
iter_value_t< iterator_t<InputRange> >,
Alloc
>;

#if defined __GNUC__ and __GNUC__ < 12
template< typename T, typename A >
explicit dynarray(const dynarray<T, A> &) -> dynarray<T, A>;
#endif

#if OEL_MEM_BOUND_DEBUG_LVL
} // namespace debug
#endif
Expand Down
26 changes: 15 additions & 11 deletions unit_test/dynarray_construct_assignop_swap_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ TEST_F(dynarrayConstructTest, deductionGuides)
static_assert(std::is_same< decltype(d)::allocator_type, StatefulAllocator<int> >());
EXPECT_EQ(d.size(), ar.size());

dynarray fromTemp(std::array<int, 1>{});
dynarray fromTemp(from_range, std::array<int, 1>{});
static_assert(std::is_same< decltype(fromTemp)::allocator_type, oel::allocator<int> >());

dynarray sizeAndVal(2, 1.f);
Expand All @@ -268,15 +268,15 @@ TEST_F(dynarrayConstructTest, deductionGuides)
TEST_F(dynarrayConstructTest, constructContiguousRange)
{
std::string str = "AbCd";
dynarray test(str);
dynarray test(from_range, str);
static_assert(std::is_same<decltype(test)::value_type, char>());
EXPECT_TRUE( 0 == str.compare(0, 4, test.data(), test.size()) );
}

TEST_F(dynarrayConstructTest, constructRangeNoCopyAssign)
{
auto il = { 1.2, 3.4 };
dynarray<MoveOnly> test(il);
dynarray<MoveOnly> test(from_range, il);
EXPECT_TRUE(test.size() == 2);
}

Expand All @@ -285,7 +285,7 @@ TEST_F(dynarrayConstructTest, constructForwardRangeNoSize)
for (auto const n : {0u, 1u, 59u})
{
std::forward_list<int> li(n, -6);
dynarray<int> d(li);
dynarray<int> d(from_range, li);
EXPECT_EQ(n, d.size());
if (0 != n)
{
Expand All @@ -298,7 +298,7 @@ TEST_F(dynarrayConstructTest, constructForwardRangeNoSize)
TEST_F(dynarrayConstructTest, constructRangeMutableBeginSize)
{
int src[1] {1};
dynarray<int> d(ToMutableBeginSizeView(src));
dynarray<int> d(from_range, ToMutableBeginSizeView(src));
EXPECT_EQ(1u, d.size());
}

Expand All @@ -307,27 +307,31 @@ TEST_F(dynarrayConstructTest, constructRangeMutableBeginSize)
TEST_F(dynarrayConstructTest, constructMoveOnlyIterator)
{
std::istringstream words{"Falling Anywhere"};
auto d = dynarray(std::views::istream<std::string>(words));
auto d = dynarray(from_range, std::views::istream<std::string>(words));
EXPECT_EQ(2u, d.size());
EXPECT_EQ("Falling", d[0]);
EXPECT_EQ("Anywhere", d[1]);
}
#endif


TEST_F(dynarrayConstructTest, copyConstruct)
{
using Al = StatefulAllocator<TrivialRelocat>;
auto x = dynarray< TrivialRelocat, Al >({TrivialRelocat{0.5}}, Al(-5));
EXPECT_EQ(1, g_allocCount.nAllocations);

auto y = dynarray(x);
EXPECT_EQ(-5, y.get_allocator().id);
EXPECT_EQ(2, g_allocCount.nAllocations);

auto z = dynarray(y, Al(7));
auto const z = dynarray(y, Al(7));
EXPECT_EQ(0.5, *z.front());
EXPECT_EQ(3, g_allocCount.nAllocations);

auto const d = dynarray(std::move(z));
EXPECT_EQ(0.5, *d.front());

auto const e = dynarray(std::move(d), Al(9));
EXPECT_EQ(9, e.get_allocator().id);
EXPECT_EQ(5, g_allocCount.nAllocations);
}

template<typename Alloc>
Expand Down Expand Up @@ -607,7 +611,7 @@ TEST_F(dynarrayConstructTest, constructInputRangeThrowing)
MoveOnly::countToThrowOn = 1;

ASSERT_THROW(
dynarray<MoveOnly>(view::subrange(f, l)),
dynarray<MoveOnly>(from_range, view::subrange(f, l)),
TestException );
}

Expand Down
2 changes: 1 addition & 1 deletion unit_test/dynarray_mutate_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,7 @@ TEST_F(dynarrayTest, erasePrecondCheck)
leakDetector->enabled = false;

dynarray<int> di{-2};
auto copy = di;
auto copy = dynarray(di);
ASSERT_DEATH( copy.erase(di.begin()), "" );
}

Expand Down
11 changes: 11 additions & 0 deletions util.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,17 @@ struct for_overwrite_t
};
inline constexpr for_overwrite_t for_overwrite; //!< An instance of for_overwrite_t for convenience

#if __cpp_lib_containers_ranges < 202202
struct from_range_t
{
explicit from_range_t() = default;
};
inline constexpr from_range_t from_range;
#else
using std::from_range_t;
using std::from_range;
#endif



//! Same as `begin(range)` with a previous `using std::begin;`. For use in classes with a member named begin
Expand Down

0 comments on commit 3972bab

Please sign in to comment.