diff --git a/auxi/assignable.h b/auxi/detail_assignable.h similarity index 100% rename from auxi/assignable.h rename to auxi/detail_assignable.h diff --git a/auxi/detail_forward.h b/auxi/forward_t.h similarity index 59% rename from auxi/detail_forward.h rename to auxi/forward_t.h index a02fbf46..b4f516f1 100644 --- a/auxi/detail_forward.h +++ b/auxi/forward_t.h @@ -1,6 +1,6 @@ #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) @@ -8,8 +8,9 @@ #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 > @@ -24,20 +25,23 @@ namespace oel::_detail and sizeof(SansRef) <= 2 * sizeof(void *) #endif > {}; +} + + +template< typename T, + typename SansRef = std::remove_reference_t, + bool IsConst = std::is_const_v +> +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 or IsConst >, + std::negation< std::is_function >, + _detail::PassByValueLikelyFaster // !IsConst implies rvalue here + >, + std::remove_cv_t, + T && + >; - template< typename T, - typename SansRef = std::remove_reference_t, - bool IsConst = std::is_const_v - > - 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 or IsConst >, - std::negation< std::is_function >, - PassByValueLikelyFaster // !IsConst implies rvalue here - >, - std::remove_cv_t, - T && - >; -} \ No newline at end of file +} // oel diff --git a/dynarray.h b/dynarray.h index 3d0b2ef7..e3f4cd43 100644 --- a/dynarray.h +++ b/dynarray.h @@ -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" @@ -168,10 +168,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... >(pos, static_cast(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) &; @@ -592,45 +594,43 @@ class dynarray exit.destroy = nullptr; return pos; } -}; - -template< typename T, typename Alloc > -template< typename... Args > -typename dynarray::iterator - dynarray::emplace(const_iterator pos, Args &&... args) & -{ -#define OEL_DYNARR_INSERT_STEP1 \ - static_assert(is_trivially_relocatable::value, \ - "insert, emplace require trivially relocatable T, see declaration of is_trivially_relocatable"); \ - \ - _debugSizeUpdater guard{_m}; \ - \ - auto pPos = const_cast(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 tmp; - _alloTrait::construct(_m, reinterpret_cast(&tmp), static_cast(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(pPos + 1), - static_cast(pPos), - bytesAfterPos ); - ++_m.end; - } - else - { pPos = _emplaceRealloc(pPos, reinterpret_cast(tmp)); + template< typename... Args > + iterator _doEmplace(const_iterator pos, Args... args) + { + #define OEL_DYNARR_INSERT_STEP1 \ + static_assert(is_trivially_relocatable::value, \ + "insert, emplace require trivially relocatable T, see declaration of is_trivially_relocatable"); \ + \ + _debugSizeUpdater guard{_m}; \ + \ + auto pPos = const_cast(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 tmp; + _alloTrait::construct(_m, reinterpret_cast(&tmp), static_cast(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(pPos + 1), + static_cast(pPos), + bytesAfterPos ); + ++_m.end; + } + else + { pPos = _emplaceRealloc(pPos, reinterpret_cast(tmp)); + } + std::memcpy( // relocate the new element to pos + static_cast(pPos), + static_cast(&tmp), + sizeof(T) ); + return _detail::MakeDynarrIter(_m, pPos); } - std::memcpy( // relocate the new element to pos - static_cast(pPos), - static_cast(&tmp), - sizeof(T) ); - return _detail::MakeDynarrIter(_m, pPos); -} +}; template< typename T, typename Alloc > template< typename Range > @@ -815,7 +815,7 @@ inline void dynarray::append(size_type count, const T & val) _growBy(count); auto const pos = _m.end; - _uninitFill::template call< _detail::ForwardT >(pos, pos + count, _m, val); + _uninitFill::template call< forward_t >(pos, pos + count, _m, val); _debugSizeUpdater guard{_m}; _m.end += count; diff --git a/unit_test/util_gtest.cpp b/unit_test/util_gtest.cpp index 7554e619..36af5668 100644 --- a/unit_test/util_gtest.cpp +++ b/unit_test/util_gtest.cpp @@ -49,67 +49,67 @@ namespace static_assert(!oel::iter_is_random_access); } -TEST(utilTest, ForwardT) +TEST(utilTest, forwardT) { - using oel::_detail::ForwardT; + using oel::forward_t; - static_assert(std::is_same_v< ForwardT, double >); - static_assert(std::is_same_v< ForwardT, double >); - static_assert(std::is_same_v< ForwardT, double >); - static_assert(std::is_same_v< ForwardT, double >); - static_assert(std::is_same_v< ForwardT, double & >); + static_assert(std::is_same_v< forward_t, double >); + static_assert(std::is_same_v< forward_t, double >); + static_assert(std::is_same_v< forward_t, double >); + static_assert(std::is_same_v< forward_t, double >); + static_assert(std::is_same_v< forward_t, double & >); - static_assert(std::is_same_v< ForwardT, int(&&)[1] >); - static_assert(std::is_same_v< ForwardT, int(&&)[1] >); - static_assert(std::is_same_v< ForwardT, int(&)[1] >); - static_assert(std::is_same_v< ForwardT, const int(&)[1] >); + static_assert(std::is_same_v< forward_t, int(&&)[1] >); + static_assert(std::is_same_v< forward_t, int(&&)[1] >); + static_assert(std::is_same_v< forward_t, int(&)[1] >); + static_assert(std::is_same_v< forward_t, const int(&)[1] >); using P = std::unique_ptr; - static_assert(std::is_same_v< ForwardT

, const P && >); - static_assert(std::is_same_v< ForwardT, const P && >); - static_assert(std::is_same_v< ForwardT

, P & >); - static_assert(std::is_same_v< ForwardT, const P & >); + static_assert(std::is_same_v< forward_t

, const P && >); + static_assert(std::is_same_v< forward_t, const P && >); + static_assert(std::is_same_v< forward_t

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

, P >); - static_assert(std::is_same_v< ForwardT

, P >); + static_assert(std::is_same_v< forward_t

, P >); + static_assert(std::is_same_v< forward_t

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

, P && >); - static_assert(std::is_same_v< ForwardT

, P && >); + static_assert(std::is_same_v< forward_t

, P && >); + static_assert(std::is_same_v< forward_t

, P && >); - static_assert(std::is_same_v< ForwardT, TrivialRelocat && >); - static_assert(std::is_same_v< ForwardT, TrivialRelocat && >); + static_assert(std::is_same_v< forward_t, TrivialRelocat && >); + static_assert(std::is_same_v< forward_t, TrivialRelocat && >); #endif { using A = std::array; - static_assert(std::is_same_v< ForwardT, A && >); - static_assert(std::is_same_v< ForwardT, A && >); - static_assert(std::is_same_v< ForwardT, const A && >); - static_assert(std::is_same_v< ForwardT, const A && >); - static_assert(std::is_same_v< ForwardT, A & >); - static_assert(std::is_same_v< ForwardT, const A & >); + static_assert(std::is_same_v< forward_t, A && >); + static_assert(std::is_same_v< forward_t, A && >); + static_assert(std::is_same_v< forward_t, const A && >); + static_assert(std::is_same_v< forward_t, const A && >); + static_assert(std::is_same_v< forward_t, A & >); + static_assert(std::is_same_v< forward_t, const A & >); } using A = std::array; - static_assert(std::is_same_v< ForwardT, A >); - static_assert(std::is_same_v< ForwardT, A >); - static_assert(std::is_same_v< ForwardT, A >); - static_assert(std::is_same_v< ForwardT, A >); - static_assert(std::is_same_v< ForwardT, A & >); + static_assert(std::is_same_v< forward_t, A >); + static_assert(std::is_same_v< forward_t, A >); + static_assert(std::is_same_v< forward_t, A >); + static_assert(std::is_same_v< forward_t, A >); + static_assert(std::is_same_v< forward_t, A & >); #if HAS_STD_PMR using Alloc = std::pmr::polymorphic_allocator; - static_assert(std::is_same_v< ForwardT, Alloc >); - static_assert(std::is_same_v< ForwardT, Alloc >); - static_assert(std::is_same_v< ForwardT, Alloc >); + static_assert(std::is_same_v< forward_t, Alloc >); + static_assert(std::is_same_v< forward_t, Alloc >); + static_assert(std::is_same_v< forward_t, Alloc >); #endif } diff --git a/view/generate.h b/view/generate.h index de5b8608..fe7ec4ac 100644 --- a/view/generate.h +++ b/view/generate.h @@ -7,7 +7,7 @@ #include "counted.h" -#include "../auxi/assignable.h" +#include "../auxi/detail_assignable.h" /** @file */ diff --git a/view/transform_iterator.h b/view/transform_iterator.h index f2acfd05..44fd2e54 100644 --- a/view/transform_iterator.h +++ b/view/transform_iterator.h @@ -7,7 +7,7 @@ #include "../util.h" // for TightPair -#include "../auxi/assignable.h" +#include "../auxi/detail_assignable.h" /** @file */