Skip to content

Commit

Permalink
_detail::ForwardT renamed forward_t, now used in dynarray::emplace
Browse files Browse the repository at this point in the history
  • Loading branch information
OleErikPeistorpet committed Jun 5, 2024
1 parent 0bd4b90 commit 9683d09
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 102 deletions.
42 changes: 23 additions & 19 deletions auxi/detail_forward.h → auxi/forward_t.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
#pragma once

// Copyright 2020 Ole Erik Peistorpet
// Copyright 2021 Ole Erik Peistorpet
//
// 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)


#include "core_util.h"


namespace oel::_detail
namespace oel
{
namespace _detail
{
// Note: false for arrays, they aren't copy/move constructible
template< typename SansRef, bool IsMutableRvalue >
Expand All @@ -24,20 +25,23 @@ namespace oel::_detail
and sizeof(SansRef) <= 2 * sizeof(void *)
#endif
> {};
}


template< typename T,
typename SansRef = std::remove_reference_t<T>,
bool IsConst = std::is_const_v<SansRef>
>
using forward_t =
std::conditional_t<
std::conjunction_v<
// Forwarding by value: a mutable lvalue reference is wrong, a function won't compile
bool_constant< !std::is_lvalue_reference_v<T> or IsConst >,
std::negation< std::is_function<SansRef> >,
_detail::PassByValueLikelyFaster<SansRef, !IsConst> // !IsConst implies rvalue here
>,
std::remove_cv_t<SansRef>,
T &&
>;

template< typename T,
typename SansRef = std::remove_reference_t<T>,
bool IsConst = std::is_const_v<SansRef>
>
using ForwardT =
std::conditional_t<
std::conjunction_v<
// Forwarding by value: a mutable lvalue reference is wrong, a function won't compile
bool_constant< !std::is_lvalue_reference_v<T> or IsConst >,
std::negation< std::is_function<SansRef> >,
PassByValueLikelyFaster<SansRef, !IsConst> // !IsConst implies rvalue here
>,
std::remove_cv_t<SansRef>,
T &&
>;
}
} // oel
84 changes: 42 additions & 42 deletions dynarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@


#include "allocator.h"
#include "auxi/detail_forward.h"
#include "auxi/dynarray_iterator.h"
#include "auxi/forward_t.h"
#include "auxi/impl_algo.h"
#include "optimize_ext/default.h"
#include "view/move.h"
Expand Down Expand Up @@ -165,10 +165,12 @@ class dynarray
iterator insert(const_iterator pos, const T & val) & { return emplace(pos, val); }

template< typename... Args >
iterator emplace(const_iterator pos, Args &&... elemInitArgs) &;
iterator emplace(const_iterator pos, Args &&... args) &
{
return _doEmplace< forward_t<Args>... >(pos, static_cast<Args &&>(args)...);
}

/**
* @brief Beware, passing an element of same array is often unsafe (otherwise same as std::vector::emplace_back)
/** @brief Beware, passing an element of same array is often unsafe (otherwise same as std::vector::emplace_back)
* @pre args shall not refer to any element of this dynarray, unless `size() < capacity()` */
template< typename... Args >
T & emplace_back(Args &&... args) &;
Expand Down Expand Up @@ -589,45 +591,43 @@ class dynarray
exit.destroy = nullptr;
return pos;
}
};

template< typename T, typename Alloc >
template< typename... Args >
typename dynarray<T, Alloc>::iterator
dynarray<T, Alloc>::emplace(const_iterator pos, Args &&... args) &
{
#define OEL_DYNARR_INSERT_STEP1 \
static_assert(is_trivially_relocatable<T>::value, \
"insert, emplace require trivially relocatable T, see declaration of is_trivially_relocatable"); \
\
_debugSizeUpdater guard{_m}; \
\
auto pPos = const_cast<T *>(to_pointer_contiguous(pos)); \
OEL_ASSERT(_m.data <= pPos and pPos <= _m.end);

OEL_DYNARR_INSERT_STEP1

// Temporary in case constructor throws or args refer to an element of this dynarray
storage_for<T> tmp;
_alloTrait::construct(_m, reinterpret_cast<T *>(&tmp), static_cast<Args &&>(args)...);
if (_m.end < _m.reservEnd)
{ // Relocate [pos, end) to [pos + 1, end + 1)
size_t const bytesAfterPos{sizeof(T) * (_m.end - pPos)};
std::memmove(
static_cast<void *>(pPos + 1),
static_cast<const void *>(pPos),
bytesAfterPos );
++_m.end;
}
else
{ pPos = _emplaceRealloc(pPos, reinterpret_cast<T &>(tmp));
template< typename... Args >
iterator _doEmplace(const_iterator pos, Args... args)
{
#define OEL_DYNARR_INSERT_STEP1 \
static_assert(is_trivially_relocatable<T>::value, \
"insert, emplace require trivially relocatable T, see declaration of is_trivially_relocatable"); \
\
_debugSizeUpdater guard{_m}; \
\
auto pPos = const_cast<T *>(to_pointer_contiguous(pos)); \
OEL_ASSERT(_m.data <= pPos and pPos <= _m.end);

OEL_DYNARR_INSERT_STEP1

// Temporary in case constructor throws or args refer to an element of this dynarray
storage_for<T> tmp;
_alloTrait::construct(_m, reinterpret_cast<T *>(&tmp), static_cast<Args &&>(args)...);
if (_m.end < _m.reservEnd)
{ // Relocate [pos, end) to [pos + 1, end + 1)
size_t const bytesAfterPos{sizeof(T) * (_m.end - pPos)};
std::memmove(
static_cast<void *>(pPos + 1),
static_cast<const void *>(pPos),
bytesAfterPos );
++_m.end;
}
else
{ pPos = _emplaceRealloc(pPos, reinterpret_cast<T &>(tmp));
}
std::memcpy( // relocate the new element to pos
static_cast<void *>(pPos),
static_cast<const void *>(&tmp),
sizeof(T) );
return _detail::MakeDynarrIter(_m, pPos);
}
std::memcpy( // relocate the new element to pos
static_cast<void *>(pPos),
static_cast<const void *>(&tmp),
sizeof(T) );
return _detail::MakeDynarrIter(_m, pPos);
}
};

template< typename T, typename Alloc >
template< typename Range >
Expand Down Expand Up @@ -812,7 +812,7 @@ inline void dynarray<T, Alloc>::append(size_type count, const T & val)
_growBy(count);

auto const pos = _m.end;
_uninitFill::template call< _detail::ForwardT<const T &> >(pos, pos + count, _m, val);
_uninitFill::template call< forward_t<const T &> >(pos, pos + count, _m, val);

_debugSizeUpdater guard{_m};
_m.end += count;
Expand Down
82 changes: 41 additions & 41 deletions unit_test/util_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,67 +49,67 @@ namespace
static_assert(!oel::iter_is_random_access<ListI>);
}

TEST(utilTest, ForwardT)
TEST(utilTest, forwardT)
{
using oel::_detail::ForwardT;
using oel::forward_t;

static_assert(std::is_same_v< ForwardT<double const>, double >);
static_assert(std::is_same_v< ForwardT<double &&>, double >);
static_assert(std::is_same_v< ForwardT<const double &&>, double >);
static_assert(std::is_same_v< ForwardT<const double &>, double >);
static_assert(std::is_same_v< ForwardT<double &>, double & >);
static_assert(std::is_same_v< forward_t<double const>, double >);
static_assert(std::is_same_v< forward_t<double &&>, double >);
static_assert(std::is_same_v< forward_t<const double &&>, double >);
static_assert(std::is_same_v< forward_t<const double &>, double >);
static_assert(std::is_same_v< forward_t<double &>, double & >);

static_assert(std::is_same_v< ForwardT<int[1]>, int(&&)[1] >);
static_assert(std::is_same_v< ForwardT<int(&&)[1]>, int(&&)[1] >);
static_assert(std::is_same_v< ForwardT<int(&)[1]>, int(&)[1] >);
static_assert(std::is_same_v< ForwardT<const int(&)[1]>, const int(&)[1] >);
static_assert(std::is_same_v< forward_t<int[1]>, int(&&)[1] >);
static_assert(std::is_same_v< forward_t<int(&&)[1]>, int(&&)[1] >);
static_assert(std::is_same_v< forward_t<int(&)[1]>, int(&)[1] >);
static_assert(std::is_same_v< forward_t<const int(&)[1]>, const int(&)[1] >);

using P = std::unique_ptr<int>;
static_assert(std::is_same_v< ForwardT<P const>, const P && >);
static_assert(std::is_same_v< ForwardT<const P &&>, const P && >);
static_assert(std::is_same_v< ForwardT<P &>, P & >);
static_assert(std::is_same_v< ForwardT<const P &>, const P & >);
static_assert(std::is_same_v< forward_t<P const>, const P && >);
static_assert(std::is_same_v< forward_t<const P &&>, const P && >);
static_assert(std::is_same_v< forward_t<P &>, P & >);
static_assert(std::is_same_v< forward_t<const P &>, const P & >);

// Small, non-trivial copy
static_assert(std::is_same_v< ForwardT<TrivialRelocat const>, const TrivialRelocat && >);
static_assert(std::is_same_v< ForwardT<const TrivialRelocat &&>, const TrivialRelocat && >);
static_assert(std::is_same_v< ForwardT<TrivialRelocat &>, TrivialRelocat & >);
static_assert(std::is_same_v< ForwardT<const TrivialRelocat &>, const TrivialRelocat & >);
static_assert(std::is_same_v< forward_t<TrivialRelocat const>, const TrivialRelocat && >);
static_assert(std::is_same_v< forward_t<const TrivialRelocat &&>, const TrivialRelocat && >);
static_assert(std::is_same_v< forward_t<TrivialRelocat &>, TrivialRelocat & >);
static_assert(std::is_same_v< forward_t<const TrivialRelocat &>, const TrivialRelocat & >);

#ifdef _MSC_VER
static_assert(std::is_same_v< ForwardT<P>, P >);
static_assert(std::is_same_v< ForwardT<P &&>, P >);
static_assert(std::is_same_v< forward_t<P>, P >);
static_assert(std::is_same_v< forward_t<P &&>, P >);

static_assert(std::is_same_v< ForwardT<TrivialRelocat>, TrivialRelocat >);
static_assert(std::is_same_v< ForwardT<TrivialRelocat &&>, TrivialRelocat >);
static_assert(std::is_same_v< forward_t<TrivialRelocat>, TrivialRelocat >);
static_assert(std::is_same_v< forward_t<TrivialRelocat &&>, TrivialRelocat >);
#else
static_assert(std::is_same_v< ForwardT<P>, P && >);
static_assert(std::is_same_v< ForwardT<P &&>, P && >);
static_assert(std::is_same_v< forward_t<P>, P && >);
static_assert(std::is_same_v< forward_t<P &&>, P && >);

static_assert(std::is_same_v< ForwardT<TrivialRelocat>, TrivialRelocat && >);
static_assert(std::is_same_v< ForwardT<TrivialRelocat &&>, TrivialRelocat && >);
static_assert(std::is_same_v< forward_t<TrivialRelocat>, TrivialRelocat && >);
static_assert(std::is_same_v< forward_t<TrivialRelocat &&>, TrivialRelocat && >);
#endif
{
using A = std::array<std::size_t, 3>;
static_assert(std::is_same_v< ForwardT<A>, A && >);
static_assert(std::is_same_v< ForwardT<A &&>, A && >);
static_assert(std::is_same_v< ForwardT<A const>, const A && >);
static_assert(std::is_same_v< ForwardT<const A &&>, const A && >);
static_assert(std::is_same_v< ForwardT<A &>, A & >);
static_assert(std::is_same_v< ForwardT<const A &>, const A & >);
static_assert(std::is_same_v< forward_t<A>, A && >);
static_assert(std::is_same_v< forward_t<A &&>, A && >);
static_assert(std::is_same_v< forward_t<A const>, const A && >);
static_assert(std::is_same_v< forward_t<const A &&>, const A && >);
static_assert(std::is_same_v< forward_t<A &>, A & >);
static_assert(std::is_same_v< forward_t<const A &>, const A & >);
}
using A = std::array<double, 1>;
static_assert(std::is_same_v< ForwardT<A const>, A >);
static_assert(std::is_same_v< ForwardT<A &&>, A >);
static_assert(std::is_same_v< ForwardT<const A &&>, A >);
static_assert(std::is_same_v< ForwardT<const A &>, A >);
static_assert(std::is_same_v< ForwardT<A &>, A & >);
static_assert(std::is_same_v< forward_t<A const>, A >);
static_assert(std::is_same_v< forward_t<A &&>, A >);
static_assert(std::is_same_v< forward_t<const A &&>, A >);
static_assert(std::is_same_v< forward_t<const A &>, A >);
static_assert(std::is_same_v< forward_t<A &>, A & >);

#if HAS_STD_PMR
using Alloc = std::pmr::polymorphic_allocator<int>;
static_assert(std::is_same_v< ForwardT<Alloc>, Alloc >);
static_assert(std::is_same_v< ForwardT<Alloc &&>, Alloc >);
static_assert(std::is_same_v< ForwardT<const Alloc &>, Alloc >);
static_assert(std::is_same_v< forward_t<Alloc>, Alloc >);
static_assert(std::is_same_v< forward_t<Alloc &&>, Alloc >);
static_assert(std::is_same_v< forward_t<const Alloc &>, Alloc >);
#endif
}

Expand Down

0 comments on commit 9683d09

Please sign in to comment.