Skip to content

Commit

Permalink
Reserving space before collection deserialization
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonBikineev committed Aug 8, 2017
1 parent 1b6b227 commit 2e90fd5
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 21 deletions.
4 changes: 2 additions & 2 deletions hpx/lcos/when_all.hpp
Expand Up @@ -387,7 +387,7 @@ namespace hpx { namespace lcos
typename std::iterator_traits<Iterator>::
difference_type difference = std::distance(begin, end);
if (difference > 0)
traits::detail::reserve_if_vector(
traits::detail::reserve_if_reservable(
lazy_values_, static_cast<std::size_t>(difference));

std::transform(begin, end, std::back_inserter(lazy_values_),
Expand All @@ -410,7 +410,7 @@ namespace hpx { namespace lcos
when_all_n(Iterator begin, std::size_t count)
{
Container values;
traits::detail::reserve_if_vector(values, count);
traits::detail::reserve_if_reservable(values, count);

traits::acquire_future_disp func;
for (std::size_t i = 0; i != count; ++i)
Expand Down
4 changes: 2 additions & 2 deletions hpx/lcos/when_any.hpp
Expand Up @@ -400,7 +400,7 @@ namespace hpx { namespace lcos
typename std::iterator_traits<Iterator>::
difference_type difference = std::distance(begin, end);
if (difference > 0)
traits::detail::reserve_if_vector(
traits::detail::reserve_if_reservable(
lazy_values_, static_cast<std::size_t>(difference));

std::transform(begin, end, std::back_inserter(lazy_values_),
Expand All @@ -424,7 +424,7 @@ namespace hpx { namespace lcos
when_any_n(Iterator begin, std::size_t count)
{
Container lazy_values_;
traits::detail::reserve_if_vector(lazy_values_, count);
traits::detail::reserve_if_reservable(lazy_values_, count);

traits::acquire_future_disp func;
for (std::size_t i = 0; i != count; ++i)
Expand Down
4 changes: 2 additions & 2 deletions hpx/lcos/when_some.hpp
Expand Up @@ -524,7 +524,7 @@ namespace hpx { namespace lcos
typename std::iterator_traits<Iterator>::
difference_type difference = std::distance(begin, end);
if (difference > 0)
traits::detail::reserve_if_vector(
traits::detail::reserve_if_reservable(
lazy_values_, static_cast<std::size_t>(difference));

std::transform(begin, end, std::back_inserter(lazy_values_),
Expand All @@ -540,7 +540,7 @@ namespace hpx { namespace lcos
error_code& ec = throws)
{
Container lazy_values_;
traits::detail::reserve_if_vector(lazy_values_, count);
traits::detail::reserve_if_reservable(lazy_values_, count);

traits::acquire_future_disp func;
for (std::size_t i = 0; i != count; ++i)
Expand Down
7 changes: 6 additions & 1 deletion hpx/runtime/serialization/detail/serialize_collection.hpp
Expand Up @@ -7,6 +7,7 @@
#define HPX_SERIALIZATION_DETAIL_SERIALIZE_COLLECTION_HPP

#include <hpx/config.hpp>
#include <hpx/traits/detail/reserve.hpp>

#include <type_traits>

Expand All @@ -16,11 +17,13 @@ namespace hpx { namespace serialization { namespace detail {
template <class Archive, class T>
void save_construct_data(Archive&, T*, unsigned)
{
HPX_ASSERT(false);
}

template <class Archive, class T>
void load_construct_data(Archive&, T* t, unsigned)
{
HPX_ASSERT(false);
::new (t) T;
}

Expand Down Expand Up @@ -85,13 +88,15 @@ namespace hpx { namespace serialization { namespace detail {
sizeof(value_type), alignof(value_type)>;

collection.clear();
hpx::traits::detail::reserve_if_reservable(collection, size);

while (size-- > 0)
{
storage_type storage;
value_type& ref = reinterpret_cast<value_type&>(storage);
load_construct_data(ar, &ref, 0);
ar >> ref;
collection.push_back(ref);
collection.push_back(std::move(ref));
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions hpx/traits/acquire_future.hpp
Expand Up @@ -126,7 +126,7 @@ namespace hpx { namespace traits
>::type
transform_future_disp(Range_ && futures, Range& values) const
{
detail::reserve_if_random_access(values, futures);
detail::reserve_if_random_access_by_range(values, futures);
std::transform(
util::begin(futures), util::end(futures),
std::back_inserter(values), acquire_future_disp());
Expand All @@ -139,7 +139,7 @@ namespace hpx { namespace traits
>::type
transform_future_disp(Range_ && futures, Range& values) const
{
detail::reserve_if_random_access(values, futures);
detail::reserve_if_random_access_by_range(values, futures);
std::transform(util::begin(futures), util::end(futures),
util::begin(values), acquire_future_disp());
}
Expand Down
2 changes: 1 addition & 1 deletion hpx/traits/acquire_shared_state.hpp
Expand Up @@ -108,7 +108,7 @@ namespace hpx { namespace traits
operator()(Range_&& futures) const
{
std::vector<shared_state_ptr> values;
detail::reserve_if_random_access(values, futures);
detail::reserve_if_random_access_by_range(values, futures);

std::transform(util::begin(futures), util::end(futures),
std::back_inserter(values), acquire_shared_state_disp());
Expand Down
38 changes: 27 additions & 11 deletions hpx/traits/detail/reserve.hpp
@@ -1,5 +1,6 @@
// Copyright (c) 2007-2016 Hartmut Kaiser
// Copyright (c) 2016 Agustin Berge
// Copyright (c) 2017 Anton Bikineev
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand All @@ -10,6 +11,7 @@
#include <hpx/config.hpp>
#include <hpx/util/range.hpp>
#include <hpx/traits/is_range.hpp>
#include <hpx/traits/has_member_xxx.hpp>

#include <cstddef>
#include <iterator>
Expand All @@ -18,16 +20,28 @@

namespace hpx { namespace traits { namespace detail
{
///////////////////////////////////////////////////////////////////////
// not every random access sequence is reservable
// so we need an explicit trait to determine this
HPX_HAS_MEMBER_XXX_TRAIT_DEF(reserve);

template <typename Range>
using is_reservable = std::integral_constant<bool,
is_range<typename std::decay<Range>::type>::value &&
has_reserve<typename std::decay<Range>::type>::value>;

///////////////////////////////////////////////////////////////////////
template <typename Container>
HPX_FORCEINLINE
void reserve_if_vector(Container&, std::size_t)
typename std::enable_if<!is_reservable<Container>::value>::type
reserve_if_reservable(Container&, std::size_t) noexcept
{
}

template <typename T>
template <typename Container>
HPX_FORCEINLINE
void reserve_if_vector(std::vector<T>& v, std::size_t n)
typename std::enable_if<is_reservable<Container>::value>::type
reserve_if_reservable(Container& v, std::size_t n)
{
v.reserve(n);
}
Expand All @@ -37,35 +51,37 @@ namespace hpx { namespace traits { namespace detail
// iterator type of the given range allow calculating the size on O(1).
template <typename Future, typename Range>
HPX_FORCEINLINE
void reserve_if_random_access(std::vector<Future>&, Range const&,
std::false_type)
void reserve_if_random_access_by_range(std::vector<Future>&,
Range const&, std::false_type) noexcept
{
}

template <typename Future, typename Range>
HPX_FORCEINLINE
void reserve_if_random_access(std::vector<Future>& v, Range const& r,
std::true_type)
void reserve_if_random_access_by_range(std::vector<Future>& v,
Range const& r, std::true_type)
{
v.reserve(util::size(r));
}

template <typename Future, typename Range>
HPX_FORCEINLINE
void reserve_if_random_access(std::vector<Future>& v, Range const& r)
void reserve_if_random_access_by_range(std::vector<Future>& v,
Range const& r)
{
typedef typename range_traits<Range>::iterator_category iterator_category;
typedef typename range_traits<Range>::iterator_category
iterator_category;

typedef typename std::is_base_of<
std::random_access_iterator_tag, iterator_category
>::type is_random_access;

reserve_if_random_access(v, r, is_random_access());
reserve_if_random_access_by_range(v, r, is_random_access());
}

template <typename Container, typename Range>
HPX_FORCEINLINE
void reserve_if_random_access(Container&, Range const&)
void reserve_if_random_access_by_range(Container&, Range const&)
{
// do nothing if it's not a vector
}
Expand Down

0 comments on commit 2e90fd5

Please sign in to comment.